123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334 |
- #include "print_job.h"
- #include <linux/memfd.h>
- #include <stdlib.h>
- #include <sys/syscall.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <unistd.h>
- #include <cstring>
- #include <string>
- #include <fpdfview.h>
- print_job::print_job(int index) : index(index) {}
- print_job::~print_job() {}
- static gboolean add_printer(GtkPrinter* printer, gpointer data) {
- auto printers = static_cast<FlValue*>(data);
- auto map = fl_value_new_map();
- auto name = gtk_printer_get_name(printer);
- auto loc = gtk_printer_get_location(printer);
- auto cmt = gtk_printer_get_description(printer);
- fl_value_set_string(map, "url", fl_value_new_string(name));
- fl_value_set_string(map, "name", fl_value_new_string(name));
- if (loc) {
- fl_value_set_string(map, "location", fl_value_new_string(loc));
- }
- if (cmt) {
- fl_value_set_string(map, "comment", fl_value_new_string(cmt));
- }
- fl_value_set_string(map, "default",
- fl_value_new_bool(gtk_printer_is_default(printer)));
- fl_value_set_string(map, "available",
- fl_value_new_bool(gtk_printer_is_active(printer) &&
- gtk_printer_accepts_pdf(printer)));
- fl_value_append(printers, map);
- return false;
- }
- FlValue* print_job::list_printers() {
- auto printers = fl_value_new_list();
- gtk_enumerate_printers(add_printer, printers, nullptr, true);
- return printers;
- }
- static GtkPrinter* _printer;
- static gboolean search_printer(GtkPrinter* printer, gpointer data) {
- auto search = static_cast<gchar*>(data);
- auto name = gtk_printer_get_name(printer);
- if (strcmp(name, search) == 0) {
- _printer = static_cast<GtkPrinter*>(g_object_ref(printer));
- return true;
- }
- return false;
- }
- bool print_job::direct_print_pdf(const gchar* name,
- const uint8_t data[],
- size_t size,
- const gchar* printer) {
- _printer = nullptr;
- auto pname = strdup(printer);
- gtk_enumerate_printers(search_printer, pname, nullptr, true);
- free(pname);
- if (!_printer) {
- return false;
- }
- auto settings = gtk_print_settings_new();
- auto setup = gtk_page_setup_new();
- printJob = gtk_print_job_new(name, _printer, settings, setup);
- this->write_job(data, size);
- g_object_unref(_printer);
- g_object_unref(settings);
- g_object_unref(setup);
- g_object_unref(printJob);
- return true;
- }
- static void job_completed(GtkPrintJob* gtk_print_job,
- gpointer user_data,
- const GError* error) {
- auto job = static_cast<print_job*>(user_data);
- if (job->dialog) {
- gtk_widget_destroy(GTK_WIDGET(job->dialog));
- }
- on_completed(job, error == nullptr,
- error != nullptr ? error->message : nullptr);
- }
- bool print_job::print_pdf(const gchar* name,
- const gchar* printer,
- double pageWidth,
- double pageHeight,
- double marginLeft,
- double marginTop,
- double marginRight,
- double marginBottom) {
- GtkPrintSettings* settings;
- GtkPageSetup* setup;
- if (printer != nullptr) {
- _printer = nullptr;
- auto pname = strdup(printer);
- gtk_enumerate_printers(search_printer, pname, nullptr, true);
- free(pname);
- if (!_printer) {
- on_completed(this, false, "Printer not found");
- return false;
- }
- settings = gtk_print_settings_new();
- setup = gtk_page_setup_new();
- } else {
- dialog = GTK_PRINT_UNIX_DIALOG(gtk_print_unix_dialog_new(name, nullptr));
- gtk_print_unix_dialog_set_manual_capabilities(
- dialog, (GtkPrintCapabilities)(GTK_PRINT_CAPABILITY_GENERATE_PDF));
- gtk_print_unix_dialog_set_embed_page_setup(dialog, true);
- gtk_print_unix_dialog_set_support_selection(dialog, false);
- gtk_widget_realize(GTK_WIDGET(dialog));
- auto loop = true;
- while (loop) {
- auto response = gtk_dialog_run(GTK_DIALOG(dialog));
- switch (response) {
- case GTK_RESPONSE_OK: {
- _printer = gtk_print_unix_dialog_get_selected_printer(
- GTK_PRINT_UNIX_DIALOG(dialog));
- settings =
- gtk_print_unix_dialog_get_settings(GTK_PRINT_UNIX_DIALOG(dialog));
- setup = gtk_print_unix_dialog_get_page_setup(
- GTK_PRINT_UNIX_DIALOG(dialog));
- gtk_widget_hide(GTK_WIDGET(dialog));
- loop = false;
- } break;
- case GTK_RESPONSE_APPLY:
- break;
- default:
- gtk_widget_destroy(GTK_WIDGET(dialog));
- on_completed(this, false, nullptr);
- return true;
- }
- }
- }
- if (!gtk_printer_accepts_pdf(_printer)) {
- on_completed(this, false, "This printer does not accept PDF jobs");
- g_object_unref(_printer);
- g_object_unref(settings);
- g_object_unref(setup);
- return false;
- }
- auto _width = gtk_page_setup_get_paper_width(setup, GTK_UNIT_POINTS);
- auto _height = gtk_page_setup_get_paper_height(setup, GTK_UNIT_POINTS);
- auto _marginLeft = gtk_page_setup_get_left_margin(setup, GTK_UNIT_POINTS);
- auto _marginTop = gtk_page_setup_get_top_margin(setup, GTK_UNIT_POINTS);
- auto _marginRight = gtk_page_setup_get_right_margin(setup, GTK_UNIT_POINTS);
- auto _marginBottom = gtk_page_setup_get_bottom_margin(setup, GTK_UNIT_POINTS);
- printJob = gtk_print_job_new(name, _printer, settings, setup);
- on_layout(this, _width, _height, _marginLeft, _marginTop, _marginRight,
- _marginBottom);
- g_object_unref(_printer);
- g_object_unref(settings);
- g_object_unref(setup);
- return true;
- }
- void print_job::write_job(const uint8_t data[], size_t size) {
- auto fd = syscall(SYS_memfd_create, "printing", 0);
- size_t offset = 0;
- ssize_t n;
- while ((n = write(fd, data + offset, size - offset)) >= 0 &&
- size - offset > 0) {
- offset += n;
- }
- if (n < 0) {
- on_completed(this, false, "Unable to copy the PDF data");
- }
- lseek(fd, 0, SEEK_SET);
- gtk_print_job_set_source_fd(printJob, fd, nullptr);
- gtk_print_job_send(printJob, job_completed, this, nullptr);
- }
- void print_job::cancel_job(const gchar* error) {}
- bool print_job::share_pdf(const uint8_t data[],
- size_t size,
- const gchar* name) {
- auto filename = "/tmp/" + std::string(name);
- auto fd = fopen(filename.c_str(), "wb");
- fwrite(data, size, 1, fd);
- fclose(fd);
- auto pid = fork();
- if (pid < 0) {
- return false;
- } else if (pid == 0) {
- execlp("xdg-open", "xdg-open", filename.c_str(), nullptr);
- }
- int status = 0;
- waitpid(pid, &status, 0);
- return status == 0;
- }
- void print_job::raster_pdf(const uint8_t data[],
- size_t size,
- const int32_t pages[],
- size_t pages_count,
- double scale) {
- FPDF_LIBRARY_CONFIG config;
- config.version = 2;
- config.m_pUserFontPaths = nullptr;
- config.m_pIsolate = nullptr;
- config.m_v8EmbedderSlot = 0;
- FPDF_InitLibraryWithConfig(&config);
- auto doc = FPDF_LoadMemDocument64(data, size, nullptr);
- if (!doc) {
- FPDF_DestroyLibrary();
- on_page_raster_end(this, "Cannot raster a malformed PDF file");
- return;
- }
- auto pageCount = FPDF_GetPageCount(doc);
- auto allPages = false;
- if (pages_count == 0) {
- allPages = true;
- pages_count = pageCount;
- }
- for (auto pn = 0; pn < pages_count; pn++) {
- auto n = allPages ? pn : pages[pn];
- if (n >= pageCount) {
- continue;
- }
- auto page = FPDF_LoadPage(doc, n);
- if (!page) {
- continue;
- }
- auto width = FPDF_GetPageWidth(page);
- auto height = FPDF_GetPageHeight(page);
- auto bWidth = static_cast<int>(width * scale);
- auto bHeight = static_cast<int>(height * scale);
- auto bitmap = FPDFBitmap_Create(bWidth, bHeight, 0);
- FPDFBitmap_FillRect(bitmap, 0, 0, bWidth, bHeight, 0xffffffff);
- FPDF_RenderPageBitmap(bitmap, page, 0, 0, bWidth, bHeight, 0,
- FPDF_ANNOT | FPDF_LCD_TEXT | FPDF_NO_NATIVETEXT);
- uint8_t* p = static_cast<uint8_t*>(FPDFBitmap_GetBuffer(bitmap));
- auto stride = FPDFBitmap_GetStride(bitmap);
- size_t l = static_cast<size_t>(bHeight * stride);
-
- for (auto y = 0; y < bHeight; y++) {
- auto offset = y * stride;
- for (auto x = 0; x < bWidth; x++) {
- auto t = p[offset];
- p[offset] = p[offset + 2];
- p[offset + 2] = t;
- offset += 4;
- }
- }
- on_page_rasterized(this, p, l, bWidth, bHeight);
- FPDFBitmap_Destroy(bitmap);
- FPDF_ClosePage(page);
- }
- FPDF_CloseDocument(doc);
- FPDF_DestroyLibrary();
- on_page_raster_end(this, nullptr);
- }
- FlValue* print_job::printing_info() {
- FlValue* result = fl_value_new_map();
- fl_value_set_string(result, "canPrint", fl_value_new_bool(true));
- fl_value_set_string(result, "canShare", fl_value_new_bool(true));
- fl_value_set_string(result, "canRaster", fl_value_new_bool(true));
- fl_value_set_string(result, "canListPrinters", fl_value_new_bool(true));
- fl_value_set_string(result, "directPrint", fl_value_new_bool(true));
- fl_value_set_string(result, "dynamicLayout", fl_value_new_bool(true));
- return result;
- }
|