David PHAM-VAN

Add Linux platform

@@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@
13 # limitations under the License. 13 # limitations under the License.
14 14
15 DART_SRC=$(shell find . -name '*.dart') 15 DART_SRC=$(shell find . -name '*.dart')
16 -CLNG_SRC=$(shell find printing/ios printing/macos printing/windows printing/android -name '*.cpp' -o -name '*.m' -o -name '*.h' -o -name '*.java') 16 +CLNG_SRC=$(shell find printing/ios printing/macos printing/windows printing/linux printing/android -name '*.cpp' -o -name '*.cc' -o -name '*.m' -o -name '*.h' -o -name '*.java')
17 SWFT_SRC=$(shell find printing/ios printing/macos -name '*.swift') 17 SWFT_SRC=$(shell find printing/ios printing/macos -name '*.swift')
18 FONTS=pdf/open-sans.ttf pdf/open-sans-bold.ttf pdf/roboto.ttf pdf/noto-sans.ttf pdf/genyomintw.ttf demo/assets/roboto1.ttf demo/assets/roboto2.ttf demo/assets/roboto3.ttf demo/assets/open-sans.ttf demo/assets/open-sans-bold.ttf pdf/hacen-tunisia.ttf pdf/material.ttf demo/assets/material.ttf 18 FONTS=pdf/open-sans.ttf pdf/open-sans-bold.ttf pdf/roboto.ttf pdf/noto-sans.ttf pdf/genyomintw.ttf demo/assets/roboto1.ttf demo/assets/roboto2.ttf demo/assets/roboto3.ttf demo/assets/open-sans.ttf demo/assets/open-sans-bold.ttf pdf/hacen-tunisia.ttf pdf/material.ttf demo/assets/material.ttf
19 COV_PORT=9292 19 COV_PORT=9292
@@ -39,3 +39,4 @@ macos/Podfile.lock @@ -39,3 +39,4 @@ macos/Podfile.lock
39 assets/*.png 39 assets/*.png
40 assets/*.jpg 40 assets/*.jpg
41 assets/logo.svg 41 assets/logo.svg
  42 +linux
@@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
8 - Improve orientation handling 8 - Improve orientation handling
9 - Improve directPrint 9 - Improve directPrint
10 - Remove the windows DLL 10 - Remove the windows DLL
  11 +- Add Linux platform
11 12
12 ## 3.7.2 13 ## 3.7.2
13 14
@@ -51,3 +51,4 @@ web @@ -51,3 +51,4 @@ web
51 README.md 51 README.md
52 test 52 test
53 windows 53 windows
  54 +linux
  1 +# Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License"); you may not
  4 +# use this file except in compliance with the License. You may obtain a copy of
  5 +# the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  11 +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  12 +# License for the specific language governing permissions and limitations under
  13 +# the License.
  14 +
  15 +cmake_minimum_required(VERSION 3.10)
  16 +set(PROJECT_NAME "printing")
  17 +project(${PROJECT_NAME} LANGUAGES CXX)
  18 +
  19 +# Download pdfium
  20 +include(../windows/DownloadProject.cmake)
  21 +download_project(
  22 + PROJ
  23 + pdfium
  24 + URL
  25 + https://github.com/bblanchon/pdfium-binaries/releases/latest/download/pdfium-linux.tgz
  26 + )
  27 +
  28 +# This value is used when generating builds using this plugin, so it must not be
  29 +# changed
  30 +set(PLUGIN_NAME "printing_plugin")
  31 +
  32 +include(${pdfium_SOURCE_DIR}/PDFiumConfig.cmake)
  33 +
  34 +# System-level dependencies.
  35 +find_package(PkgConfig REQUIRED)
  36 +pkg_check_modules(GTKUnixPrint REQUIRED IMPORTED_TARGET gtk+-unix-print-3.0)
  37 +
  38 +add_library(${PLUGIN_NAME} SHARED
  39 + "printing_plugin.cc"
  40 + "include/printing/printing_plugin.h"
  41 + "print_job.cc"
  42 + "print_job.h"
  43 + )
  44 +
  45 +apply_standard_settings(${PLUGIN_NAME})
  46 +set_target_properties(${PLUGIN_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden)
  47 +target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL)
  48 +target_include_directories(${PLUGIN_NAME}
  49 + INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include")
  50 +target_link_libraries(${PLUGIN_NAME} PRIVATE flutter)
  51 +target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK PkgConfig::GTKUnixPrint)
  52 +target_link_libraries(${PLUGIN_NAME} PRIVATE pdfium)
  53 +
  54 +# List of absolute paths to libraries that should be bundled with the plugin
  55 +set(printing_bundled_libraries
  56 + "${PDFium_LIBRARY}"
  57 + PARENT_SCOPE)
  1 +/*
  2 + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +#ifndef FLUTTER_PLUGIN_PRINTING_PLUGIN_H_
  18 +#define FLUTTER_PLUGIN_PRINTING_PLUGIN_H_
  19 +
  20 +#include <flutter_linux/flutter_linux.h>
  21 +
  22 +G_BEGIN_DECLS
  23 +
  24 +#ifdef FLUTTER_PLUGIN_IMPL
  25 +#define FLUTTER_PLUGIN_EXPORT __attribute__((visibility("default")))
  26 +#else
  27 +#define FLUTTER_PLUGIN_EXPORT
  28 +#endif
  29 +
  30 +typedef struct _PrintingPlugin PrintingPlugin;
  31 +typedef struct {
  32 + GObjectClass parent_class;
  33 +} PrintingPluginClass;
  34 +
  35 +FLUTTER_PLUGIN_EXPORT GType printing_plugin_get_type();
  36 +
  37 +FLUTTER_PLUGIN_EXPORT void printing_plugin_register_with_registrar(
  38 + FlPluginRegistrar* registrar);
  39 +
  40 +G_END_DECLS
  41 +
  42 +#endif // FLUTTER_PLUGIN_PRINTING_PLUGIN_H_
  1 +/*
  2 + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +#include "print_job.h"
  18 +
  19 +#include <stdlib.h>
  20 +#include <sys/mman.h>
  21 +#include <sys/types.h>
  22 +#include <sys/wait.h>
  23 +#include <string>
  24 +
  25 +#include <fpdfview.h>
  26 +
  27 +print_job::print_job(int index) : index(index) {}
  28 +
  29 +print_job::~print_job() {}
  30 +
  31 +static gboolean add_printer(GtkPrinter* printer, gpointer data) {
  32 + auto printers = static_cast<FlValue*>(data);
  33 +
  34 + auto map = fl_value_new_map();
  35 + auto name = gtk_printer_get_name(printer);
  36 + auto loc = gtk_printer_get_location(printer);
  37 + auto cmt = gtk_printer_get_description(printer);
  38 +
  39 + fl_value_set_string(map, "url", fl_value_new_string(name));
  40 + fl_value_set_string(map, "name", fl_value_new_string(name));
  41 + if (loc) {
  42 + fl_value_set_string(map, "location", fl_value_new_string(loc));
  43 + }
  44 + if (cmt) {
  45 + fl_value_set_string(map, "comment", fl_value_new_string(cmt));
  46 + }
  47 + fl_value_set_string(map, "default",
  48 + fl_value_new_bool(gtk_printer_is_default(printer)));
  49 + fl_value_set_string(map, "available",
  50 + fl_value_new_bool(gtk_printer_is_active(printer) &&
  51 + gtk_printer_accepts_pdf(printer)));
  52 +
  53 + fl_value_append(printers, map);
  54 + return false;
  55 +}
  56 +
  57 +FlValue* print_job::list_printers() {
  58 + auto printers = fl_value_new_list();
  59 + gtk_enumerate_printers(add_printer, printers, nullptr, true);
  60 + return printers;
  61 +}
  62 +
  63 +static GtkPrinter* _printer;
  64 +
  65 +static gboolean search_printer(GtkPrinter* printer, gpointer data) {
  66 + auto search = static_cast<gchar*>(data);
  67 + auto name = gtk_printer_get_name(printer);
  68 +
  69 + if (strcmp(name, search) == 0) {
  70 + _printer = static_cast<GtkPrinter*>(g_object_ref(printer));
  71 + return true;
  72 + }
  73 +
  74 + return false;
  75 +}
  76 +
  77 +bool print_job::direct_print_pdf(const gchar* name,
  78 + const uint8_t data[],
  79 + size_t size,
  80 + const gchar* printer) {
  81 + _printer = nullptr;
  82 + auto pname = strdup(printer);
  83 + gtk_enumerate_printers(search_printer, pname, nullptr, true);
  84 + free(pname);
  85 +
  86 + if (!_printer) {
  87 + return false;
  88 + }
  89 +
  90 + auto settings = gtk_print_settings_new();
  91 + auto setup = gtk_page_setup_new();
  92 + printJob = gtk_print_job_new(name, _printer, settings, setup);
  93 + this->write_job(data, size);
  94 +
  95 + g_object_unref(_printer);
  96 + g_object_unref(settings);
  97 + g_object_unref(setup);
  98 + g_object_unref(printJob);
  99 +
  100 + return true;
  101 +}
  102 +
  103 +static void job_completed(GtkPrintJob* gtk_print_job,
  104 + gpointer user_data,
  105 + const GError* error) {
  106 + auto job = static_cast<print_job*>(user_data);
  107 + on_completed(job, error == nullptr,
  108 + error != nullptr ? error->message : nullptr);
  109 +}
  110 +
  111 +bool print_job::print_pdf(const gchar* name,
  112 + double pageWidth,
  113 + double pageHeight,
  114 + double marginLeft,
  115 + double marginTop,
  116 + double marginRight,
  117 + double marginBottom) {
  118 + documentName = strdup(name);
  119 + auto dialog =
  120 + GTK_PRINT_UNIX_DIALOG(gtk_print_unix_dialog_new(documentName, nullptr));
  121 + gtk_print_unix_dialog_set_manual_capabilities(
  122 + dialog, (GtkPrintCapabilities)(GTK_PRINT_CAPABILITY_GENERATE_PDF));
  123 +
  124 + gtk_widget_realize(GTK_WIDGET(dialog));
  125 +
  126 + auto response = gtk_dialog_run(GTK_DIALOG(dialog));
  127 + gtk_widget_hide(GTK_WIDGET(dialog));
  128 +
  129 + switch (response) {
  130 + case GTK_RESPONSE_OK: {
  131 + GtkPrinter* printer = gtk_print_unix_dialog_get_selected_printer(
  132 + GTK_PRINT_UNIX_DIALOG(dialog));
  133 + if (!gtk_printer_accepts_pdf(printer)) {
  134 + on_completed(this, false, "This printer does not accept PDF jobs");
  135 + break;
  136 + }
  137 +
  138 + GtkPrintSettings* settings =
  139 + gtk_print_unix_dialog_get_settings(GTK_PRINT_UNIX_DIALOG(dialog));
  140 + GtkPageSetup* setup =
  141 + gtk_print_unix_dialog_get_page_setup(GTK_PRINT_UNIX_DIALOG(dialog));
  142 +
  143 + auto width = gtk_page_setup_get_page_width(setup, GTK_UNIT_POINTS);
  144 + auto height = gtk_page_setup_get_page_height(setup, GTK_UNIT_POINTS);
  145 + auto marginLeft = gtk_page_setup_get_left_margin(setup, GTK_UNIT_POINTS);
  146 + auto marginTop = gtk_page_setup_get_top_margin(setup, GTK_UNIT_POINTS);
  147 + auto marginRight =
  148 + gtk_page_setup_get_right_margin(setup, GTK_UNIT_POINTS);
  149 + auto marginBottom =
  150 + gtk_page_setup_get_bottom_margin(setup, GTK_UNIT_POINTS);
  151 +
  152 + printJob = gtk_print_job_new(name, printer, settings, setup);
  153 +
  154 + on_layout(this, width, height, marginLeft, marginTop, marginRight,
  155 + marginBottom);
  156 +
  157 + g_object_unref(settings);
  158 + gtk_widget_destroy(GTK_WIDGET(dialog));
  159 +
  160 + return true;
  161 + }
  162 + case GTK_RESPONSE_DELETE_EVENT: // Fall through.
  163 + case GTK_RESPONSE_CANCEL: // Cancel
  164 + case GTK_RESPONSE_APPLY: // Preview
  165 + break;
  166 + }
  167 +
  168 + gtk_widget_destroy(GTK_WIDGET(dialog));
  169 + on_completed(this, false, nullptr);
  170 + return true;
  171 +}
  172 +
  173 +void print_job::write_job(const uint8_t data[], size_t size) {
  174 + auto fd = memfd_create("printing", 0);
  175 + size_t offset = 0;
  176 + size_t n;
  177 + while ((n = write(fd, data + offset, size - offset)) >= 0 &&
  178 + size - offset > 0) {
  179 + offset += n;
  180 + }
  181 + if (n < 0) {
  182 + on_completed(this, false, "Unable to copy the PDF data");
  183 + }
  184 +
  185 + lseek(fd, 0, SEEK_SET);
  186 +
  187 + gtk_print_job_set_source_fd(printJob, fd, nullptr);
  188 + gtk_print_job_send(printJob, job_completed, this, nullptr);
  189 +}
  190 +
  191 +void print_job::cancel_job(const gchar* error) {}
  192 +
  193 +bool print_job::share_pdf(const uint8_t data[],
  194 + size_t size,
  195 + const gchar* name) {
  196 + auto filename = "/tmp/" + std::string(name);
  197 +
  198 + auto fd = fopen(filename.c_str(), "wb");
  199 + fwrite(data, size, 1, fd);
  200 + fclose(fd);
  201 +
  202 + auto pid = fork();
  203 +
  204 + if (pid < 0) { // error occurred
  205 + return false;
  206 + } else if (pid == 0) { // child process
  207 + execlp("xdg-open", "xdg-open", filename.c_str(), nullptr);
  208 + }
  209 +
  210 + int status = 0;
  211 + waitpid(pid, &status, 0);
  212 +
  213 + return status == 0;
  214 +}
  215 +
  216 +void print_job::raster_pdf(const uint8_t data[],
  217 + size_t size,
  218 + const int32_t pages[],
  219 + size_t pages_count,
  220 + double scale) {
  221 + FPDF_InitLibraryWithConfig(nullptr);
  222 +
  223 + auto doc = FPDF_LoadMemDocument64(data, size, nullptr);
  224 + if (!doc) {
  225 + FPDF_DestroyLibrary();
  226 + on_page_raster_end(this);
  227 + return;
  228 + }
  229 +
  230 + auto pageCount = FPDF_GetPageCount(doc);
  231 + auto allPages = false;
  232 +
  233 + if (pages_count == 0) {
  234 + allPages = true;
  235 + pages_count = pageCount;
  236 + }
  237 +
  238 + for (auto pn = 0; pn < pages_count; pn++) {
  239 + auto n = allPages ? pn : pages[pn];
  240 + if (n >= pageCount) {
  241 + continue;
  242 + }
  243 +
  244 + auto page = FPDF_LoadPage(doc, n);
  245 + if (!page) {
  246 + continue;
  247 + }
  248 +
  249 + auto width = FPDF_GetPageWidth(page);
  250 + auto height = FPDF_GetPageHeight(page);
  251 +
  252 + auto bWidth = static_cast<int>(width * scale);
  253 + auto bHeight = static_cast<int>(height * scale);
  254 +
  255 + auto bitmap = FPDFBitmap_Create(bWidth, bHeight, 0);
  256 + FPDFBitmap_FillRect(bitmap, 0, 0, bWidth, bHeight, 0xffffffff);
  257 +
  258 + FPDF_RenderPageBitmap(bitmap, page, 0, 0, bWidth, bHeight, 0, FPDF_ANNOT);
  259 +
  260 + uint8_t* p = static_cast<uint8_t*>(FPDFBitmap_GetBuffer(bitmap));
  261 + auto stride = FPDFBitmap_GetStride(bitmap);
  262 + size_t l = static_cast<size_t>(bHeight * stride);
  263 +
  264 + // BGRA to RGBA conversion
  265 + for (auto y = 0; y < bHeight; y++) {
  266 + auto offset = y * stride;
  267 + for (auto x = 0; x < bWidth; x++) {
  268 + auto t = p[offset];
  269 + p[offset] = p[offset + 2];
  270 + p[offset + 2] = t;
  271 + offset += 4;
  272 + }
  273 + }
  274 +
  275 + on_page_rasterized(this, p, l, bWidth, bHeight);
  276 +
  277 + FPDFBitmap_Destroy(bitmap);
  278 + }
  279 +
  280 + FPDF_CloseDocument(doc);
  281 +
  282 + FPDF_DestroyLibrary();
  283 +
  284 + on_page_raster_end(this);
  285 +}
  286 +
  287 +FlValue* print_job::printing_info() {
  288 + FlValue* result = fl_value_new_map();
  289 + fl_value_set_string(result, "canPrint", fl_value_new_bool(true));
  290 + fl_value_set_string(result, "canShare", fl_value_new_bool(true));
  291 + fl_value_set_string(result, "canRaster", fl_value_new_bool(true));
  292 + fl_value_set_string(result, "canListPrinters", fl_value_new_bool(true));
  293 + fl_value_set_string(result, "directPrint", fl_value_new_bool(true));
  294 + fl_value_set_string(result, "dynamicLayout", fl_value_new_bool(true));
  295 + return result;
  296 +}
  1 +/*
  2 + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +#ifndef PRINTING_PLUGIN_PRINT_JOB_H_
  18 +#define PRINTING_PLUGIN_PRINT_JOB_H_
  19 +
  20 +#include <flutter_linux/flutter_linux.h>
  21 +#include <gtk/gtk.h>
  22 +#include <gtk/gtkunixprint.h>
  23 +
  24 +class print_job {
  25 + private:
  26 + const int index;
  27 + char* documentName = nullptr;
  28 + GtkPrintJob* printJob;
  29 +
  30 + public:
  31 + print_job(int index);
  32 +
  33 + ~print_job();
  34 +
  35 + int get_id() { return index; };
  36 +
  37 + static FlValue* list_printers();
  38 +
  39 + bool direct_print_pdf(const gchar* name,
  40 + const uint8_t data[],
  41 + size_t size,
  42 + const gchar* printer);
  43 +
  44 + bool print_pdf(const gchar* name,
  45 + double pageWidth,
  46 + double pageHeight,
  47 + double marginLeft,
  48 + double marginTop,
  49 + double marginRight,
  50 + double marginBottom);
  51 +
  52 + void write_job(const uint8_t data[], size_t size);
  53 +
  54 + void cancel_job(const gchar* error);
  55 +
  56 + static bool share_pdf(const uint8_t data[], size_t size, const gchar* name);
  57 +
  58 + void raster_pdf(const uint8_t data[],
  59 + size_t size,
  60 + const int32_t pages[],
  61 + size_t pages_count,
  62 + double scale);
  63 +
  64 + static FlValue* printing_info();
  65 +};
  66 +
  67 +void on_page_rasterized(print_job* job,
  68 + const uint8_t* data,
  69 + size_t size,
  70 + int width,
  71 + int height);
  72 +
  73 +void on_page_raster_end(print_job* job);
  74 +
  75 +void on_layout(print_job* job,
  76 + double pageWidth,
  77 + double pageHeight,
  78 + double marginLeft,
  79 + double marginTop,
  80 + double marginRight,
  81 + double marginBottom);
  82 +
  83 +void on_completed(print_job* job, bool completed, const char* error);
  84 +
  85 +#endif // PRINTING_PLUGIN_PRINT_JOB_H_
  1 +/*
  2 + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +#include "include/printing/printing_plugin.h"
  18 +
  19 +#include <memory>
  20 +
  21 +#include <flutter_linux/flutter_linux.h>
  22 +#include <gtk/gtk.h>
  23 +
  24 +#include "print_job.h"
  25 +
  26 +#define PRINTING_PLUGIN(obj) \
  27 + (G_TYPE_CHECK_INSTANCE_CAST((obj), printing_plugin_get_type(), \
  28 + PrintingPlugin))
  29 +
  30 +struct _PrintingPlugin {
  31 + GObject parent_instance;
  32 +};
  33 +
  34 +G_DEFINE_TYPE(PrintingPlugin, printing_plugin, g_object_get_type())
  35 +
  36 +static FlMethodChannel* channel;
  37 +
  38 +// Called when a method call is received from Flutter.
  39 +static void printing_plugin_handle_method_call(PrintingPlugin* self,
  40 + FlMethodCall* method_call) {
  41 + g_autoptr(FlMethodResponse) response = nullptr;
  42 +
  43 + const gchar* method = fl_method_call_get_name(method_call);
  44 + FlValue* args = fl_method_call_get_args(method_call);
  45 +
  46 + if (strcmp(method, "printingInfo") == 0) {
  47 + g_autoptr(FlValue) result = print_job::printing_info();
  48 + response = FL_METHOD_RESPONSE(fl_method_success_response_new(result));
  49 +
  50 + } else if (strcmp(method, "listPrinters") == 0) {
  51 + g_autoptr(FlValue) result = print_job::list_printers();
  52 + response = FL_METHOD_RESPONSE(fl_method_success_response_new(result));
  53 +
  54 + } else if (strcmp(method, "printPdf") == 0) {
  55 + auto name = fl_value_get_string(fl_value_lookup_string(args, "name"));
  56 + auto jobNum = fl_value_get_int(fl_value_lookup_string(args, "job"));
  57 + auto pageWidth = fl_value_get_float(fl_value_lookup_string(args, "width"));
  58 + auto pageHeight =
  59 + fl_value_get_float(fl_value_lookup_string(args, "height"));
  60 + auto marginLeft =
  61 + fl_value_get_float(fl_value_lookup_string(args, "marginLeft"));
  62 + auto marginTop =
  63 + fl_value_get_float(fl_value_lookup_string(args, "marginTop"));
  64 + auto marginRight =
  65 + fl_value_get_float(fl_value_lookup_string(args, "marginRight"));
  66 + auto marginBottom =
  67 + fl_value_get_float(fl_value_lookup_string(args, "marginBottom"));
  68 +
  69 + auto job = new print_job(jobNum);
  70 + auto res = job->print_pdf(name, pageWidth, pageHeight, marginLeft,
  71 + marginTop, marginRight, marginBottom);
  72 + if (!res) {
  73 + delete job;
  74 + }
  75 + g_autoptr(FlValue) result = fl_value_new_int(res);
  76 + response = FL_METHOD_RESPONSE(fl_method_success_response_new(result));
  77 +
  78 + } else if (strcmp(method, "directPrintPdf") == 0) {
  79 + auto jobNum = fl_value_get_int(fl_value_lookup_string(args, "job"));
  80 + auto name = fl_value_get_string(fl_value_lookup_string(args, "name"));
  81 + auto printer = fl_value_get_string(fl_value_lookup_string(args, "printer"));
  82 + auto doc = fl_value_get_uint8_list(fl_value_lookup_string(args, "doc"));
  83 + auto size = fl_value_get_length(fl_value_lookup_string(args, "doc"));
  84 +
  85 + auto job = std::make_unique<print_job>(jobNum);
  86 + auto res = job->direct_print_pdf(name, doc, size, printer);
  87 + g_autoptr(FlValue) result = fl_value_new_int(res);
  88 + response = FL_METHOD_RESPONSE(fl_method_success_response_new(result));
  89 +
  90 + } else if (strcmp(method, "sharePdf") == 0) {
  91 + auto name = fl_value_get_string(fl_value_lookup_string(args, "name"));
  92 + auto doc = fl_value_get_uint8_list(fl_value_lookup_string(args, "doc"));
  93 + auto size = fl_value_get_length(fl_value_lookup_string(args, "doc"));
  94 +
  95 + auto res = print_job::share_pdf(doc, size, name);
  96 + g_autoptr(FlValue) result = fl_value_new_int(res);
  97 + response = FL_METHOD_RESPONSE(fl_method_success_response_new(result));
  98 +
  99 + } else if (strcmp(method, "rasterPdf") == 0) {
  100 + auto doc = fl_value_get_uint8_list(fl_value_lookup_string(args, "doc"));
  101 + auto size = fl_value_get_length(fl_value_lookup_string(args, "doc"));
  102 + auto v_pages = fl_value_lookup_string(args, "pages");
  103 + int32_t* pages = nullptr;
  104 + size_t pages_count = 0;
  105 + if (fl_value_get_type(v_pages) == FL_VALUE_TYPE_LIST) {
  106 + pages_count = fl_value_get_length(v_pages);
  107 + pages = (int32_t*)malloc(sizeof(int32_t) * pages_count);
  108 + for (auto n = 0; n < pages_count; n++) {
  109 + pages[n] = fl_value_get_int(fl_value_get_list_value(v_pages, n));
  110 + }
  111 + }
  112 + auto scale = fl_value_get_float(fl_value_lookup_string(args, "scale"));
  113 + auto jobNum = fl_value_get_int(fl_value_lookup_string(args, "job"));
  114 + auto job = std::make_unique<print_job>(jobNum);
  115 + job->raster_pdf(doc, size, pages, pages_count, scale);
  116 + free(pages);
  117 +
  118 + g_autoptr(FlValue) result = fl_value_new_bool(true);
  119 + response = FL_METHOD_RESPONSE(fl_method_success_response_new(result));
  120 +
  121 + } else {
  122 + response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new());
  123 + }
  124 +
  125 + fl_method_call_respond(method_call, response, nullptr);
  126 +}
  127 +
  128 +static void printing_plugin_dispose(GObject* object) {
  129 + G_OBJECT_CLASS(printing_plugin_parent_class)->dispose(object);
  130 +}
  131 +
  132 +static void printing_plugin_class_init(PrintingPluginClass* klass) {
  133 + G_OBJECT_CLASS(klass)->dispose = printing_plugin_dispose;
  134 +}
  135 +
  136 +static void printing_plugin_init(PrintingPlugin* self) {}
  137 +
  138 +static void method_call_cb(FlMethodChannel* channel,
  139 + FlMethodCall* method_call,
  140 + gpointer user_data) {
  141 + PrintingPlugin* plugin = PRINTING_PLUGIN(user_data);
  142 + printing_plugin_handle_method_call(plugin, method_call);
  143 +}
  144 +
  145 +void printing_plugin_register_with_registrar(FlPluginRegistrar* registrar) {
  146 + PrintingPlugin* plugin =
  147 + PRINTING_PLUGIN(g_object_new(printing_plugin_get_type(), nullptr));
  148 +
  149 + g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
  150 + channel = fl_method_channel_new(fl_plugin_registrar_get_messenger(registrar),
  151 + "net.nfet.printing", FL_METHOD_CODEC(codec));
  152 + fl_method_channel_set_method_call_handler(
  153 + channel, method_call_cb, g_object_ref(plugin), g_object_unref);
  154 +
  155 + g_object_unref(plugin);
  156 +}
  157 +
  158 +void on_page_rasterized(print_job* job,
  159 + const uint8_t* data,
  160 + size_t size,
  161 + int width,
  162 + int height) {
  163 + g_autoptr(FlValue) map = fl_value_new_map();
  164 + fl_value_set_string(map, "image", fl_value_new_uint8_list(data, size));
  165 + fl_value_set_string(map, "width", fl_value_new_int(width));
  166 + fl_value_set_string(map, "height", fl_value_new_int(height));
  167 + fl_value_set_string(map, "job", fl_value_new_int(job->get_id()));
  168 +
  169 + fl_method_channel_invoke_method(channel, "onPageRasterized", map, nullptr,
  170 + nullptr, nullptr);
  171 +}
  172 +
  173 +void on_page_raster_end(print_job* job) {
  174 + g_autoptr(FlValue) map = fl_value_new_map();
  175 + fl_value_set_string(map, "job", fl_value_new_int(job->get_id()));
  176 +
  177 + fl_method_channel_invoke_method(channel, "onPageRasterEnd", map, nullptr,
  178 + nullptr, nullptr);
  179 +}
  180 +
  181 +static void on_layout_response_cb(GObject* object,
  182 + GAsyncResult* result,
  183 + gpointer user_data) {
  184 + print_job* job = static_cast<print_job*>(user_data);
  185 + g_autoptr(GError) error = nullptr;
  186 + g_autoptr(FlMethodResponse) response =
  187 + fl_method_channel_invoke_method_finish(channel, result, &error);
  188 + if (!response) {
  189 + job->cancel_job(error->message);
  190 + }
  191 +
  192 + if (FL_IS_METHOD_SUCCESS_RESPONSE(response)) {
  193 + FlValue* result = fl_method_success_response_get_result(
  194 + FL_METHOD_SUCCESS_RESPONSE(response));
  195 + auto data = fl_value_get_uint8_list(result);
  196 + auto size = fl_value_get_length(result);
  197 + job->write_job(data, size);
  198 + } else if (FL_IS_METHOD_ERROR_RESPONSE(response)) {
  199 + FlMethodErrorResponse* error_response = FL_METHOD_ERROR_RESPONSE(response);
  200 + // fl_method_error_response_get_code(error_response);
  201 + auto message = fl_method_error_response_get_message(error_response);
  202 + // fl_method_error_response_get_details(error_response);
  203 + job->cancel_job(message);
  204 + }
  205 +}
  206 +
  207 +void on_layout(print_job* job,
  208 + double pageWidth,
  209 + double pageHeight,
  210 + double marginLeft,
  211 + double marginTop,
  212 + double marginRight,
  213 + double marginBottom) {
  214 + g_autoptr(FlValue) map = fl_value_new_map();
  215 + fl_value_set_string(map, "job", fl_value_new_int(job->get_id()));
  216 + fl_value_set_string(map, "width", fl_value_new_float(pageWidth));
  217 + fl_value_set_string(map, "height", fl_value_new_float(pageHeight));
  218 + fl_value_set_string(map, "marginLeft", fl_value_new_float(marginLeft));
  219 + fl_value_set_string(map, "marginTop", fl_value_new_float(marginTop));
  220 + fl_value_set_string(map, "marginRight", fl_value_new_float(marginRight));
  221 + fl_value_set_string(map, "marginBottom", fl_value_new_float(marginBottom));
  222 +
  223 + fl_method_channel_invoke_method(channel, "onLayout", map, nullptr,
  224 + on_layout_response_cb, job);
  225 +}
  226 +
  227 +void on_completed(print_job* job, bool completed, const char* error) {
  228 + g_autoptr(FlValue) map = fl_value_new_map();
  229 + fl_value_set_string(map, "job", fl_value_new_int(job->get_id()));
  230 + fl_value_set_string(map, "completed", fl_value_new_bool(completed));
  231 + if (error != nullptr) {
  232 + fl_value_set_string(map, "error", fl_value_new_string(error));
  233 + }
  234 +
  235 + fl_method_channel_invoke_method(channel, "onCompleted", map, nullptr, nullptr,
  236 + nullptr);
  237 +}
@@ -38,6 +38,8 @@ flutter: @@ -38,6 +38,8 @@ flutter:
38 pluginClass: PrintingPlugin 38 pluginClass: PrintingPlugin
39 ios: 39 ios:
40 pluginClass: PrintingPlugin 40 pluginClass: PrintingPlugin
  41 + linux:
  42 + pluginClass: PrintingPlugin
41 macos: 43 macos:
42 pluginClass: PrintingPlugin 44 pluginClass: PrintingPlugin
43 web: 45 web: