@@ -40,6 +40,7 @@ Canvas::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) {
4040 Local<ObjectTemplate> proto = ctor->PrototypeTemplate ();
4141 Nan::SetPrototypeMethod (ctor, " toBuffer" , ToBuffer);
4242 Nan::SetPrototypeMethod (ctor, " streamPNGSync" , StreamPNGSync);
43+ Nan::SetPrototypeMethod (ctor, " streamPDFSync" , StreamPDFSync);
4344#ifdef HAVE_JPEG
4445 Nan::SetPrototypeMethod (ctor, " streamJPEGSync" , StreamJPEGSync);
4546#endif
@@ -434,6 +435,84 @@ NAN_METHOD(Canvas::StreamPNGSync) {
434435 return ;
435436}
436437
438+ /*
439+ * Canvas::StreamPDF FreeCallback
440+ */
441+
442+ void stream_pdf_free (char *, void *) {}
443+
444+ /*
445+ * Canvas::StreamPDF callback.
446+ */
447+
448+ static cairo_status_t
449+ streamPDF (void *c, const uint8_t *data, unsigned len) {
450+ Nan::HandleScope scope;
451+ closure_t *closure = static_cast <closure_t *>(c);
452+ Local<Object> buf = Nan::NewBuffer (const_cast <char *>(reinterpret_cast <const char *>(data)), len, stream_pdf_free, 0 ).ToLocalChecked ();
453+ Local<Value> argv[3 ] = {
454+ Nan::Null ()
455+ , buf
456+ , Nan::New<Number>(len) };
457+ Nan::MakeCallback (Nan::GetCurrentContext ()->Global (), closure->fn , 3 , argv);
458+ return CAIRO_STATUS_SUCCESS;
459+ }
460+
461+
462+ cairo_status_t canvas_write_to_pdf_stream (cairo_surface_t *surface, cairo_write_func_t write_func, void *closure) {
463+ closure_t *pdf_closure = static_cast <closure_t *>(closure);
464+ size_t whole_chunks = pdf_closure->len / PAGE_SIZE;
465+ size_t remainder = pdf_closure->len - whole_chunks * PAGE_SIZE;
466+
467+ for (size_t i = 0 ; i < whole_chunks; ++i) {
468+ write_func (pdf_closure, &pdf_closure->data [i * PAGE_SIZE], PAGE_SIZE);
469+ }
470+
471+ if (remainder) {
472+ write_func (pdf_closure, &pdf_closure->data [whole_chunks * PAGE_SIZE], remainder);
473+ }
474+
475+ return CAIRO_STATUS_SUCCESS;
476+ }
477+
478+ /*
479+ * Stream PDF data synchronously.
480+ */
481+
482+ NAN_METHOD (Canvas::StreamPDFSync) {
483+ if (!info[0 ]->IsFunction ())
484+ return Nan::ThrowTypeError (" callback function required" );
485+
486+ Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.Holder ());
487+
488+ if (!canvas->isPDF ())
489+ return Nan::ThrowTypeError (" wrong canvas type" );
490+
491+ cairo_surface_finish (canvas->surface ());
492+
493+ closure_t closure;
494+ closure.data = static_cast <closure_t *>(canvas->closure ())->data ;
495+ closure.len = static_cast <closure_t *>(canvas->closure ())->len ;
496+ closure.fn = info[0 ].As <Function>();
497+
498+ Nan::TryCatch try_catch;
499+
500+ cairo_status_t status = canvas_write_to_pdf_stream (canvas->surface (), streamPDF, &closure);
501+
502+ if (try_catch.HasCaught ()) {
503+ try_catch.ReThrow ();
504+ } else if (status) {
505+ Local<Value> error = Canvas::Error (status);
506+ Nan::Call (closure.fn , Nan::GetCurrentContext ()->Global (), 1 , &error);
507+ } else {
508+ Local<Value> argv[3 ] = {
509+ Nan::Null ()
510+ , Nan::Null ()
511+ , Nan::New<Uint32>(0 ) };
512+ Nan::Call (closure.fn , Nan::GetCurrentContext ()->Global (), 3 , argv);
513+ }
514+ }
515+
437516/*
438517 * Stream JPEG data synchronously.
439518 */
0 commit comments