Showing
10 changed files
with
723 additions
and
1 deletions
@@ -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 |
printing/linux/CMakeLists.txt
0 → 100644
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_ |
printing/linux/print_job.cc
0 → 100644
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 | +} |
printing/linux/print_job.h
0 → 100644
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_ |
printing/linux/printing_plugin.cc
0 → 100644
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: |
-
Please register or login to post a comment