From 7c0d66b58d0834a7f5e0510612b2587a8a11418b Mon Sep 17 00:00:00 2001 From: Bozhidar Tonchev Date: Fri, 15 Sep 2023 11:20:31 +0300 Subject: [PATCH 01/12] Printing plugin initial commit --- CMakeLists.txt | 5 +++++ src/plugins/printing.c | 43 ++++++++++++++++++++++++++++++++++++++++++ src/plugins/printing.h | 9 +++++++++ 3 files changed, 57 insertions(+) create mode 100644 src/plugins/printing.c create mode 100644 src/plugins/printing.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a22e514..d892d56f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,7 @@ option(BUILD_GSTREAMER_VIDEO_PLAYER_PLUGIN "Include the gstreamer based video pl option(BUILD_GSTREAMER_AUDIO_PLAYER_PLUGIN "Include the gstreamer based audio plugins in the finished binary." ON) option(TRY_BUILD_GSTREAMER_VIDEO_PLAYER_PLUGIN "Don't throw an error if the gstreamer libs aren't found, instead just don't build the gstreamer video player plugin in that case." ON) option(TRY_BUILD_GSTREAMER_AUDIO_PLAYER_PLUGIN "Don't throw an error if the gstreamer libs aren't found, instead just don't build gstreamer audio plugin." ON) +option(BUILD_PRINTING_PLUGIN "Include the printing plugin in the finished binary." ON) option(ENABLE_OPENGL "Build with EGL/OpenGL rendering support." ON) option(TRY_ENABLE_OPENGL "Don't throw an error if EGL/OpenGL aren't found, instead just build without EGL/OpenGL support in that case." ON) option(ENABLE_VULKAN "Build with Vulkan rendering support." OFF) @@ -338,6 +339,10 @@ if (BUILD_GSTREAMER_AUDIO_PLAYER_PLUGIN) endif() endif() +if (BUILD_PRINTING_PLUGIN) + target_sources(flutterpi_module PRIVATE src/plugins/printing.c) +endif() + # Needed so dart VM can actually resolve symbols in the same # executable. (For dart:ffi DynamicLibrary.executable / DynamicLibrary.process) target_link_options(flutterpi_module PUBLIC -rdynamic) diff --git a/src/plugins/printing.c b/src/plugins/printing.c new file mode 100644 index 00000000..a4319105 --- /dev/null +++ b/src/plugins/printing.c @@ -0,0 +1,43 @@ +#include "plugins/printing.h" +#include "flutter-pi.h" +#include "pluginregistry.h" +#include "util/logging.h" + +static int on_raster_pdf(struct platch_obj *object, FlutterPlatformMessageResponseHandle *responseHandle) { + //TODO handle + return platch_respond( + responseHandle, + &(struct platch_obj){ .codec = kStandardMethodCallResponse, .success = true, .std_result = { .type = kStdTrue } } + ); +} + +static int on_receive(char *channel, struct platch_obj *object, FlutterPlatformMessageResponseHandle *responseHandle) { + const char *method; + method = object->method; + + if (streq(method, "rasterPdf")) { + return on_raster_pdf(object, responseHandle); + } + + return platch_respond_not_implemented(responseHandle); +} + +enum plugin_init_result printing_init(struct flutterpi *flutterpi, void **userdata_out) { + int ok; + + ok = plugin_registry_set_receiver_locked(PRINTING_CHANNEL, kStandardMethodCall, on_receive); + if (ok != 0) { + return PLUGIN_INIT_RESULT_ERROR; + } + + *userdata_out = NULL; + + return PLUGIN_INIT_RESULT_INITIALIZED; +} + +void printing_deinit(struct flutterpi *flutterpi, void *userdata) { + plugin_registry_remove_receiver_v2_locked(flutterpi_get_plugin_registry(flutterpi), PRINTING_CHANNEL); + return 0; +} + +FLUTTERPI_PLUGIN("printing plugin", printing_plugin, printing_init, printing_deinit) \ No newline at end of file diff --git a/src/plugins/printing.h b/src/plugins/printing.h new file mode 100644 index 00000000..a066f94e --- /dev/null +++ b/src/plugins/printing.h @@ -0,0 +1,9 @@ +#ifndef _PRINTING_PLUGIN_H +#define _PRINTING_PLUGIN_H + +#include +#include + +#define PRINTING_CHANNEL "net.nfet.printing" + +#endif From 9b66792dd8cb768df918a2ec265f9094eb601203 Mon Sep 17 00:00:00 2001 From: Bozhidar Tonchev Date: Fri, 15 Sep 2023 11:53:13 +0300 Subject: [PATCH 02/12] Initial raster_pdf implementation --- CMakeLists.txt | 2 + src/plugins/printing.c | 180 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 181 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d892d56f..5e1cb171 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -340,7 +340,9 @@ if (BUILD_GSTREAMER_AUDIO_PLAYER_PLUGIN) endif() if (BUILD_PRINTING_PLUGIN) + pkg_check_modules(IMAGEMAGICK IMPORTED_TARGET MagickWand) target_sources(flutterpi_module PRIVATE src/plugins/printing.c) + target_link_libraries(flutterpi_module PUBLIC PkgConfig::IMAGEMAGICK) endif() # Needed so dart VM can actually resolve symbols in the same diff --git a/src/plugins/printing.c b/src/plugins/printing.c index a4319105..a5a8f059 100644 --- a/src/plugins/printing.c +++ b/src/plugins/printing.c @@ -2,9 +2,187 @@ #include "flutter-pi.h" #include "pluginregistry.h" #include "util/logging.h" +#include + +static void on_page_raster_end(int64_t job, const char* error) { + struct std_value response = STDMAP1(STDSTRING("job"), STDINT32(job)); + if (error != NULL) { + response = STDMAP2(STDSTRING("job"), STDINT32(job), STDSTRING("error"), STDSTRING(error)); + + LOG_ERROR("%s\n", error); + } + + platch_call_std(PRINTING_CHANNEL, "onPageRasterEnd", &response, NULL, NULL); +} + +static void on_page_rasterized(int64_t job, const uint8_t* data, size_t size, int width, int height) { + struct std_value image = (struct std_value){ .type = kStdUInt8Array, .uint8array = data, .size = size }; + + struct std_value response = STDMAP4( + STDSTRING("image"), + image, + STDSTRING("width"), + STDINT32(width), + STDSTRING("height"), + STDINT32(height), + STDSTRING("job"), + STDINT32(job) + ); + + platch_call_std(PRINTING_CHANNEL, "onPageRasterized", &response, NULL, NULL); +} + +static void raster_pdf(const uint8_t *data, size_t size, const int32_t *pages, size_t pages_count, double scale, int64_t job) { + MagickWand *wand = NULL; + PixelWand *color = NULL; + + int width, height; + + MagickWandGenesis(); + + wand = NewMagickWand(); + + color = NewPixelWand(); + PixelSetColor(color, "white"); + + MagickBooleanType result = MagickReadImageBlob(wand, data, size); + if(result != MagickTrue){ + on_page_raster_end(job, "Cannot read images from PDF blob."); + return; + } + + MagickResetIterator(wand); + + auto all_pages = false; + if (pages_count == 0) { + all_pages = true; + pages_count = MagickGetNumberImages(wand); + } + + int current_page = 0; + while(MagickNextImage(wand) != MagickFalse){ + if(!all_pages){ + bool shouldRasterize = false; + + //Check if current page is set to be rasterized + for(auto pn = 0; pn < pages_count; pn++) { + if(pages[pn] == current_page){ + shouldRasterize = true; + break; + } + } + + if(!shouldRasterize){ + current_page++; + continue; + } + } + + // Get the image's width and height + width = MagickGetImageWidth(wand); + height = MagickGetImageHeight(wand); + + int32_t bWidth = width * scale; + int32_t bHeight = height * scale; + + MagickResizeImage(wand, bWidth, bHeight, GaussianFilter); + + MagickSetImageAlphaChannel(wand, RemoveAlphaChannel); + MagickSetImageBackgroundColor(wand, color); + wand = MagickMergeImageLayers(wand, FlattenLayer); + + MagickSetImageFormat(wand, "bmp"); + MagickTransformImageColorspace(wand, RGBColorspace); + + size_t page_size; + uint8_t *page_data = MagickGetImageBlob(wand, &page_size); + + printf("(uint8_t) ["); + for (int i = 0; i < page_size; i++) { + printf("%02X", page_data[i]); + } + + on_page_rasterized(job, page_data, page_size, bWidth, bHeight); + + MagickRelinquishMemory(page_data); + + current_page++; + } + + /* Clean up */ + if(wand){ + wand = DestroyMagickWand(wand); + } + + if(color){ + color = DestroyPixelWand(color); + } + + MagickWandTerminus(); + + on_page_raster_end(job, NULL); +} static int on_raster_pdf(struct platch_obj *object, FlutterPlatformMessageResponseHandle *responseHandle) { - //TODO handle + struct std_value *args, *tmp; + uint8_t *data; + size_t data_length; + double scale; + int64_t job; + + args = &object->std_arg; + + if (args == NULL || !STDVALUE_IS_MAP(*args)) { + return platch_respond_illegal_arg_std(responseHandle, "Expected `arg` to be a map."); + } + + tmp = stdmap_get_str(&object->std_arg, "doc"); + if (tmp == NULL || (*tmp).type != kStdUInt8Array ) { + LOG_ERROR("Call missing mandatory parameter doc.\n"); + return platch_respond_illegal_arg_std(responseHandle, "Expected `arg['doc'] to be a uint8_t list."); + } + + data = tmp->uint8array; + data_length = tmp->size; + + int32_t* pages; + size_t pages_count; + tmp = stdmap_get_str(&object->std_arg, "pages"); + if (tmp != NULL || STDVALUE_IS_LIST(*tmp)) { + pages_count = tmp->size; + pages = (int32_t*)malloc(sizeof(int32_t) * pages_count); + for (size_t n = 0; n < pages_count; n++) { + struct std_value page = tmp->list[n]; + + if(!STDVALUE_IS_INT(page)){ + continue; + } + + pages[n] = page.int32_value; + } + } + + tmp = stdmap_get_str(&object->std_arg, "scale"); + if (tmp == NULL || !STDVALUE_IS_FLOAT(*tmp)) { + LOG_ERROR("Call missing mandatory parameter scale.\n"); + return platch_respond_illegal_arg_std(responseHandle, "Expected `arg['scale'] to be a double."); + } + + scale = STDVALUE_AS_FLOAT(*tmp); + + tmp = stdmap_get_str(&object->std_arg, "job"); + if (tmp == NULL || !STDVALUE_IS_INT(*tmp)) { + LOG_ERROR("Call missing mandatory parameter job.\n"); + return platch_respond_illegal_arg_std(responseHandle, "Expected `arg['job'] to be an int."); + } + + job = STDVALUE_AS_INT(*tmp); + + //Rasterize + raster_pdf(data, data_length, pages, pages_count, scale, job); + + free(pages); + return platch_respond( responseHandle, &(struct platch_obj){ .codec = kStandardMethodCallResponse, .success = true, .std_result = { .type = kStdTrue } } From 5c46f9e27a180f453ac8a9055d835db05545e9e5 Mon Sep 17 00:00:00 2001 From: Bozhidar Tonchev Date: Tue, 19 Sep 2023 17:46:57 +0300 Subject: [PATCH 03/12] Update printing.c --- src/plugins/printing.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/plugins/printing.c b/src/plugins/printing.c index a5a8f059..0330cfe2 100644 --- a/src/plugins/printing.c +++ b/src/plugins/printing.c @@ -97,11 +97,6 @@ static void raster_pdf(const uint8_t *data, size_t size, const int32_t *pages, s size_t page_size; uint8_t *page_data = MagickGetImageBlob(wand, &page_size); - printf("(uint8_t) ["); - for (int i = 0; i < page_size; i++) { - printf("%02X", page_data[i]); - } - on_page_rasterized(job, page_data, page_size, bWidth, bHeight); MagickRelinquishMemory(page_data); From ad7ff5ea52e5b8aabdbe8965249b7ca32150561c Mon Sep 17 00:00:00 2001 From: Bozhidar Tonchev Date: Fri, 15 Sep 2023 11:53:13 +0300 Subject: [PATCH 04/12] Initial raster_pdf implementation --- CMakeLists.txt | 2 + src/plugins/printing.c | 175 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 176 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d892d56f..5e1cb171 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -340,7 +340,9 @@ if (BUILD_GSTREAMER_AUDIO_PLAYER_PLUGIN) endif() if (BUILD_PRINTING_PLUGIN) + pkg_check_modules(IMAGEMAGICK IMPORTED_TARGET MagickWand) target_sources(flutterpi_module PRIVATE src/plugins/printing.c) + target_link_libraries(flutterpi_module PUBLIC PkgConfig::IMAGEMAGICK) endif() # Needed so dart VM can actually resolve symbols in the same diff --git a/src/plugins/printing.c b/src/plugins/printing.c index a4319105..0330cfe2 100644 --- a/src/plugins/printing.c +++ b/src/plugins/printing.c @@ -2,9 +2,182 @@ #include "flutter-pi.h" #include "pluginregistry.h" #include "util/logging.h" +#include + +static void on_page_raster_end(int64_t job, const char* error) { + struct std_value response = STDMAP1(STDSTRING("job"), STDINT32(job)); + if (error != NULL) { + response = STDMAP2(STDSTRING("job"), STDINT32(job), STDSTRING("error"), STDSTRING(error)); + + LOG_ERROR("%s\n", error); + } + + platch_call_std(PRINTING_CHANNEL, "onPageRasterEnd", &response, NULL, NULL); +} + +static void on_page_rasterized(int64_t job, const uint8_t* data, size_t size, int width, int height) { + struct std_value image = (struct std_value){ .type = kStdUInt8Array, .uint8array = data, .size = size }; + + struct std_value response = STDMAP4( + STDSTRING("image"), + image, + STDSTRING("width"), + STDINT32(width), + STDSTRING("height"), + STDINT32(height), + STDSTRING("job"), + STDINT32(job) + ); + + platch_call_std(PRINTING_CHANNEL, "onPageRasterized", &response, NULL, NULL); +} + +static void raster_pdf(const uint8_t *data, size_t size, const int32_t *pages, size_t pages_count, double scale, int64_t job) { + MagickWand *wand = NULL; + PixelWand *color = NULL; + + int width, height; + + MagickWandGenesis(); + + wand = NewMagickWand(); + + color = NewPixelWand(); + PixelSetColor(color, "white"); + + MagickBooleanType result = MagickReadImageBlob(wand, data, size); + if(result != MagickTrue){ + on_page_raster_end(job, "Cannot read images from PDF blob."); + return; + } + + MagickResetIterator(wand); + + auto all_pages = false; + if (pages_count == 0) { + all_pages = true; + pages_count = MagickGetNumberImages(wand); + } + + int current_page = 0; + while(MagickNextImage(wand) != MagickFalse){ + if(!all_pages){ + bool shouldRasterize = false; + + //Check if current page is set to be rasterized + for(auto pn = 0; pn < pages_count; pn++) { + if(pages[pn] == current_page){ + shouldRasterize = true; + break; + } + } + + if(!shouldRasterize){ + current_page++; + continue; + } + } + + // Get the image's width and height + width = MagickGetImageWidth(wand); + height = MagickGetImageHeight(wand); + + int32_t bWidth = width * scale; + int32_t bHeight = height * scale; + + MagickResizeImage(wand, bWidth, bHeight, GaussianFilter); + + MagickSetImageAlphaChannel(wand, RemoveAlphaChannel); + MagickSetImageBackgroundColor(wand, color); + wand = MagickMergeImageLayers(wand, FlattenLayer); + + MagickSetImageFormat(wand, "bmp"); + MagickTransformImageColorspace(wand, RGBColorspace); + + size_t page_size; + uint8_t *page_data = MagickGetImageBlob(wand, &page_size); + + on_page_rasterized(job, page_data, page_size, bWidth, bHeight); + + MagickRelinquishMemory(page_data); + + current_page++; + } + + /* Clean up */ + if(wand){ + wand = DestroyMagickWand(wand); + } + + if(color){ + color = DestroyPixelWand(color); + } + + MagickWandTerminus(); + + on_page_raster_end(job, NULL); +} static int on_raster_pdf(struct platch_obj *object, FlutterPlatformMessageResponseHandle *responseHandle) { - //TODO handle + struct std_value *args, *tmp; + uint8_t *data; + size_t data_length; + double scale; + int64_t job; + + args = &object->std_arg; + + if (args == NULL || !STDVALUE_IS_MAP(*args)) { + return platch_respond_illegal_arg_std(responseHandle, "Expected `arg` to be a map."); + } + + tmp = stdmap_get_str(&object->std_arg, "doc"); + if (tmp == NULL || (*tmp).type != kStdUInt8Array ) { + LOG_ERROR("Call missing mandatory parameter doc.\n"); + return platch_respond_illegal_arg_std(responseHandle, "Expected `arg['doc'] to be a uint8_t list."); + } + + data = tmp->uint8array; + data_length = tmp->size; + + int32_t* pages; + size_t pages_count; + tmp = stdmap_get_str(&object->std_arg, "pages"); + if (tmp != NULL || STDVALUE_IS_LIST(*tmp)) { + pages_count = tmp->size; + pages = (int32_t*)malloc(sizeof(int32_t) * pages_count); + for (size_t n = 0; n < pages_count; n++) { + struct std_value page = tmp->list[n]; + + if(!STDVALUE_IS_INT(page)){ + continue; + } + + pages[n] = page.int32_value; + } + } + + tmp = stdmap_get_str(&object->std_arg, "scale"); + if (tmp == NULL || !STDVALUE_IS_FLOAT(*tmp)) { + LOG_ERROR("Call missing mandatory parameter scale.\n"); + return platch_respond_illegal_arg_std(responseHandle, "Expected `arg['scale'] to be a double."); + } + + scale = STDVALUE_AS_FLOAT(*tmp); + + tmp = stdmap_get_str(&object->std_arg, "job"); + if (tmp == NULL || !STDVALUE_IS_INT(*tmp)) { + LOG_ERROR("Call missing mandatory parameter job.\n"); + return platch_respond_illegal_arg_std(responseHandle, "Expected `arg['job'] to be an int."); + } + + job = STDVALUE_AS_INT(*tmp); + + //Rasterize + raster_pdf(data, data_length, pages, pages_count, scale, job); + + free(pages); + return platch_respond( responseHandle, &(struct platch_obj){ .codec = kStandardMethodCallResponse, .success = true, .std_result = { .type = kStdTrue } } From 25bac8e77e096827188aaaa2e5b85971d92a548b Mon Sep 17 00:00:00 2001 From: Bojidar Tonchev Date: Tue, 19 Sep 2023 22:54:32 +0300 Subject: [PATCH 05/12] Initial on_printing_info implementation --- src/plugins/printing.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/plugins/printing.c b/src/plugins/printing.c index 0330cfe2..06764c91 100644 --- a/src/plugins/printing.c +++ b/src/plugins/printing.c @@ -184,11 +184,33 @@ static int on_raster_pdf(struct platch_obj *object, FlutterPlatformMessageRespon ); } +static int on_printing_info(struct platch_obj *object, FlutterPlatformMessageResponseHandle *responseHandle) { + return platch_respond( + responseHandle, + &PLATCH_OBJ_STD_MSG(STDMAP6( + STDSTRING("canPrint"), + STDBOOL(false), + STDSTRING("canShare"), + STDBOOL(false), + STDSTRING("canRaster"), + STDBOOL(true), + STDSTRING("canListPrinters"), + STDBOOL(false), + STDSTRING("directPrint"), + STDBOOL(false), + STDSTRING("dynamicLayout"), + STDBOOL(false) + )) + ); +} + static int on_receive(char *channel, struct platch_obj *object, FlutterPlatformMessageResponseHandle *responseHandle) { const char *method; method = object->method; - if (streq(method, "rasterPdf")) { + if (streq(method, "printingInfo")) { + return on_printing_info(object, responseHandle); + } else if (streq(method, "rasterPdf")) { return on_raster_pdf(object, responseHandle); } From ef5c23c295dbc9090acd6e024e1c25d3b50affef Mon Sep 17 00:00:00 2001 From: Bozhidar Tonchev Date: Wed, 20 Sep 2023 09:23:02 +0300 Subject: [PATCH 06/12] Update printing.c Update printing.c Update printing.c Update printing.c Update printing.c Update printing.c Update printing.c Update printing.c Update printing.c Update printing.c Update printing.c Update printing.c Update printing.c Update printing.c Update printing.c Update printing.c Update printing.c Update printing.c Update printing.c Update printing.c Update printing.c Update printing.c Update printing.c Update printing.c Update printing.c Update printing.c --- src/plugins/printing.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/plugins/printing.c b/src/plugins/printing.c index 06764c91..e1283518 100644 --- a/src/plugins/printing.c +++ b/src/plugins/printing.c @@ -85,14 +85,8 @@ static void raster_pdf(const uint8_t *data, size_t size, const int32_t *pages, s int32_t bWidth = width * scale; int32_t bHeight = height * scale; - MagickResizeImage(wand, bWidth, bHeight, GaussianFilter); - - MagickSetImageAlphaChannel(wand, RemoveAlphaChannel); - MagickSetImageBackgroundColor(wand, color); - wand = MagickMergeImageLayers(wand, FlattenLayer); - + MagickResizeImage(wand, bWidth, bHeight, LanczosFilter); MagickSetImageFormat(wand, "bmp"); - MagickTransformImageColorspace(wand, RGBColorspace); size_t page_size; uint8_t *page_data = MagickGetImageBlob(wand, &page_size); From f3735dc8bffdac8d992eb00b7336fbd0019782d7 Mon Sep 17 00:00:00 2001 From: Bozhidar Tonchev Date: Wed, 20 Sep 2023 17:31:25 +0300 Subject: [PATCH 07/12] Update printing.c --- src/plugins/printing.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/plugins/printing.c b/src/plugins/printing.c index e1283518..e82f8112 100644 --- a/src/plugins/printing.c +++ b/src/plugins/printing.c @@ -178,23 +178,23 @@ static int on_raster_pdf(struct platch_obj *object, FlutterPlatformMessageRespon ); } -static int on_printing_info(struct platch_obj *object, FlutterPlatformMessageResponseHandle *responseHandle) { - return platch_respond( +static int on_printing_info(struct platch_obj *object, FlutterPlatformMessageResponseHandle *responseHandle) { + return platch_respond( responseHandle, &PLATCH_OBJ_STD_MSG(STDMAP6( - STDSTRING("canPrint"), - STDBOOL(false), - STDSTRING("canShare"), - STDBOOL(false), - STDSTRING("canRaster"), - STDBOOL(true), - STDSTRING("canListPrinters"), - STDBOOL(false), - STDSTRING("directPrint"), - STDBOOL(false), - STDSTRING("dynamicLayout"), - STDBOOL(false) - )) + STDSTRING("canPrint"), + STDBOOL(false), + STDSTRING("canShare"), + STDBOOL(false), + STDSTRING("canRaster"), + STDBOOL(true), + STDSTRING("canListPrinters"), + STDBOOL(false), + STDSTRING("directPrint"), + STDBOOL(false), + STDSTRING("dynamicLayout"), + STDBOOL(false) + )) ); } @@ -202,7 +202,7 @@ static int on_receive(char *channel, struct platch_obj *object, FlutterPlatformM const char *method; method = object->method; - if (streq(method, "printingInfo")) { + if (streq(method, "printingInfo")) { return on_printing_info(object, responseHandle); } else if (streq(method, "rasterPdf")) { return on_raster_pdf(object, responseHandle); From c38d64b506fc45ae35df406a11d87d6420d458b8 Mon Sep 17 00:00:00 2001 From: Bozhidar Tonchev Date: Wed, 20 Sep 2023 17:35:33 +0300 Subject: [PATCH 08/12] * Disable printing plugin by default --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e1cb171..0221937a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,7 @@ option(BUILD_GSTREAMER_VIDEO_PLAYER_PLUGIN "Include the gstreamer based video pl option(BUILD_GSTREAMER_AUDIO_PLAYER_PLUGIN "Include the gstreamer based audio plugins in the finished binary." ON) option(TRY_BUILD_GSTREAMER_VIDEO_PLAYER_PLUGIN "Don't throw an error if the gstreamer libs aren't found, instead just don't build the gstreamer video player plugin in that case." ON) option(TRY_BUILD_GSTREAMER_AUDIO_PLAYER_PLUGIN "Don't throw an error if the gstreamer libs aren't found, instead just don't build gstreamer audio plugin." ON) -option(BUILD_PRINTING_PLUGIN "Include the printing plugin in the finished binary." ON) +option(BUILD_PRINTING_PLUGIN "Include the printing plugin in the finished binary." OFF) option(ENABLE_OPENGL "Build with EGL/OpenGL rendering support." ON) option(TRY_ENABLE_OPENGL "Don't throw an error if EGL/OpenGL aren't found, instead just build without EGL/OpenGL support in that case." ON) option(ENABLE_VULKAN "Build with Vulkan rendering support." OFF) From a56658c39e0037761a9f6d8c92ada2dd42288c3c Mon Sep 17 00:00:00 2001 From: Bozhidar Tonchev Date: Thu, 21 Sep 2023 10:02:29 +0300 Subject: [PATCH 09/12] Update README.md --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 8918141a..32df44a0 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,11 @@ If you encounter issues running flutter-pi on any of the supported platforms lis ```shell $ sudo apt install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-bad1.0-dev gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-ugly gstreamer1.0-plugins-bad gstreamer1.0-libav gstreamer1.0-alsa ``` + + If you want to use the [printing](#printing), install these too: + ```shell + $ sudo apt install imagemagick + ```
More Info @@ -414,6 +419,13 @@ To use the gstreamer video player, just rebuild flutter-pi (delete your build fo And then, just use the stuff in the official [video_player](https://pub.dev/packages/video_player) package. (`VideoPlayer`, `VideoPlayerController`, etc, there's nothing specific you need to do on the dart-side) +### printing +Printing is a plugin that allows Flutter apps to generate and print documents to android or ios compatible printers. + +To use the printing plugin, just rebuild flutter-pi (delete your build folder and reconfigure) and make sure the necessary printing packages are installed. (See [dependencies](#dependencies)) + +And then, just use the stuff in the official [printing](https://pub.dev/packages/printing) package. + ## 📊 Performance ### Graphics Performance Graphics performance is actually pretty good. With most of the apps inside the `flutter SDK -> examples -> catalog` directory I get smooth 50-60fps on the Pi 4 2GB and Pi 3 A+. @@ -433,6 +445,7 @@ This is why I created my own (userspace) touchscreen driver, for improved latenc | linux_spidev ([package](https://pub.dev/packages/linux_spidev/)) ([repo](https://github.com/ardera/flutter_packages/tree/main/packages/linux_spidev)) | 🖨 peripherals | Hannes Winkler | SPI bus support for dart/flutter, uses kernel interfaces directly for more performance. | | dart_periphery ([package](https://pub.dev/packages/dart_periphery)) ([repo](https://github.com/pezi/dart_periphery)) | 🖨 peripherals | [Peter Sauer](https://github.com/pezi/) | All-in-one package GPIO, I2C, SPI, Serial, PWM, Led, MMIO support using c-periphery. | | flutterpi_gstreamer_video_player ([package](https://pub.dev/packages/flutterpi_gstreamer_video_player)) ([repo](https://github.com/ardera/flutter_packages/tree/main/packages/flutterpi_gstreamer_video_player)) | ⏯️ multimedia | Hannes Winkler | Official video player implementation for flutter-pi. See [GStreamer video player](#gstreamer-video-player) section above. | +| printing ([package](https://pub.dev/packages/printing)) ([repo](https://github.com/DavBfr/dart_pdf)) | 🖨 peripherals | David PHAM-VAN | Generate and print documents to android or ios compatible printers. See [printing](#printing) section above. | ## 💬 Discord There a `#custom-embedders` channel on the [flutter discord](https://github.com/flutter/flutter/wiki/Chat) which you can use if you have any questions regarding flutter-pi or generally, anything related to embedding the engine for which you don't want to open issue about or write an email. From 773a5f9dd3aa58e754587825781ce7c22d40cdb4 Mon Sep 17 00:00:00 2001 From: Bozhidar Tonchev Date: Thu, 21 Sep 2023 17:28:17 +0300 Subject: [PATCH 10/12] * Fix debug build --- src/plugins/printing.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/plugins/printing.c b/src/plugins/printing.c index e82f8112..a165c3dc 100644 --- a/src/plugins/printing.c +++ b/src/plugins/printing.c @@ -4,7 +4,7 @@ #include "util/logging.h" #include -static void on_page_raster_end(int64_t job, const char* error) { +static void on_page_raster_end(int64_t job, char* error) { struct std_value response = STDMAP1(STDSTRING("job"), STDINT32(job)); if (error != NULL) { response = STDMAP2(STDSTRING("job"), STDINT32(job), STDSTRING("error"), STDSTRING(error)); @@ -53,7 +53,7 @@ static void raster_pdf(const uint8_t *data, size_t size, const int32_t *pages, s MagickResetIterator(wand); - auto all_pages = false; + bool all_pages = false; if (pages_count == 0) { all_pages = true; pages_count = MagickGetNumberImages(wand); @@ -65,7 +65,7 @@ static void raster_pdf(const uint8_t *data, size_t size, const int32_t *pages, s bool shouldRasterize = false; //Check if current page is set to be rasterized - for(auto pn = 0; pn < pages_count; pn++) { + for(size_t pn = 0; pn < pages_count; pn++) { if(pages[pn] == current_page){ shouldRasterize = true; break; @@ -114,7 +114,7 @@ static void raster_pdf(const uint8_t *data, size_t size, const int32_t *pages, s static int on_raster_pdf(struct platch_obj *object, FlutterPlatformMessageResponseHandle *responseHandle) { struct std_value *args, *tmp; - uint8_t *data; + const uint8_t *data; size_t data_length; double scale; int64_t job; @@ -179,6 +179,8 @@ static int on_raster_pdf(struct platch_obj *object, FlutterPlatformMessageRespon } static int on_printing_info(struct platch_obj *object, FlutterPlatformMessageResponseHandle *responseHandle) { + (void) object; + return platch_respond( responseHandle, &PLATCH_OBJ_STD_MSG(STDMAP6( @@ -199,6 +201,8 @@ static int on_printing_info(struct platch_obj *object, FlutterPlatformMessageRes } static int on_receive(char *channel, struct platch_obj *object, FlutterPlatformMessageResponseHandle *responseHandle) { + (void) channel; + const char *method; method = object->method; @@ -212,6 +216,8 @@ static int on_receive(char *channel, struct platch_obj *object, FlutterPlatformM } enum plugin_init_result printing_init(struct flutterpi *flutterpi, void **userdata_out) { + (void) flutterpi; + int ok; ok = plugin_registry_set_receiver_locked(PRINTING_CHANNEL, kStandardMethodCall, on_receive); @@ -225,8 +231,9 @@ enum plugin_init_result printing_init(struct flutterpi *flutterpi, void **userda } void printing_deinit(struct flutterpi *flutterpi, void *userdata) { + (void) userdata; + plugin_registry_remove_receiver_v2_locked(flutterpi_get_plugin_registry(flutterpi), PRINTING_CHANNEL); - return 0; } FLUTTERPI_PLUGIN("printing plugin", printing_plugin, printing_init, printing_deinit) \ No newline at end of file From fdd0574f920c255c46604be6e50b42b679e2e53c Mon Sep 17 00:00:00 2001 From: Bozhidar Tonchev Date: Thu, 28 Sep 2023 13:42:15 +0300 Subject: [PATCH 11/12] * Apply naming style for some variables --- src/plugins/printing.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/plugins/printing.c b/src/plugins/printing.c index a165c3dc..10ac2e54 100644 --- a/src/plugins/printing.c +++ b/src/plugins/printing.c @@ -46,7 +46,7 @@ static void raster_pdf(const uint8_t *data, size_t size, const int32_t *pages, s PixelSetColor(color, "white"); MagickBooleanType result = MagickReadImageBlob(wand, data, size); - if(result != MagickTrue){ + if(result != MagickTrue) { on_page_raster_end(job, "Cannot read images from PDF blob."); return; } @@ -60,19 +60,19 @@ static void raster_pdf(const uint8_t *data, size_t size, const int32_t *pages, s } int current_page = 0; - while(MagickNextImage(wand) != MagickFalse){ + while(MagickNextImage(wand) != MagickFalse) { if(!all_pages){ bool shouldRasterize = false; //Check if current page is set to be rasterized for(size_t pn = 0; pn < pages_count; pn++) { - if(pages[pn] == current_page){ + if(pages[pn] == current_page) { shouldRasterize = true; break; } } - if(!shouldRasterize){ + if(!shouldRasterize) { current_page++; continue; } @@ -112,7 +112,7 @@ static void raster_pdf(const uint8_t *data, size_t size, const int32_t *pages, s on_page_raster_end(job, NULL); } -static int on_raster_pdf(struct platch_obj *object, FlutterPlatformMessageResponseHandle *responseHandle) { +static int on_raster_pdf(struct platch_obj *object, FlutterPlatformMessageResponseHandle *response_handle) { struct std_value *args, *tmp; const uint8_t *data; size_t data_length; @@ -122,13 +122,13 @@ static int on_raster_pdf(struct platch_obj *object, FlutterPlatformMessageRespon args = &object->std_arg; if (args == NULL || !STDVALUE_IS_MAP(*args)) { - return platch_respond_illegal_arg_std(responseHandle, "Expected `arg` to be a map."); + return platch_respond_illegal_arg_std(response_handle, "Expected `arg` to be a map."); } tmp = stdmap_get_str(&object->std_arg, "doc"); if (tmp == NULL || (*tmp).type != kStdUInt8Array ) { LOG_ERROR("Call missing mandatory parameter doc.\n"); - return platch_respond_illegal_arg_std(responseHandle, "Expected `arg['doc'] to be a uint8_t list."); + return platch_respond_illegal_arg_std(response_handle, "Expected `arg['doc'] to be a uint8_t list."); } data = tmp->uint8array; @@ -154,7 +154,7 @@ static int on_raster_pdf(struct platch_obj *object, FlutterPlatformMessageRespon tmp = stdmap_get_str(&object->std_arg, "scale"); if (tmp == NULL || !STDVALUE_IS_FLOAT(*tmp)) { LOG_ERROR("Call missing mandatory parameter scale.\n"); - return platch_respond_illegal_arg_std(responseHandle, "Expected `arg['scale'] to be a double."); + return platch_respond_illegal_arg_std(response_handle, "Expected `arg['scale'] to be a double."); } scale = STDVALUE_AS_FLOAT(*tmp); @@ -162,7 +162,7 @@ static int on_raster_pdf(struct platch_obj *object, FlutterPlatformMessageRespon tmp = stdmap_get_str(&object->std_arg, "job"); if (tmp == NULL || !STDVALUE_IS_INT(*tmp)) { LOG_ERROR("Call missing mandatory parameter job.\n"); - return platch_respond_illegal_arg_std(responseHandle, "Expected `arg['job'] to be an int."); + return platch_respond_illegal_arg_std(response_handle, "Expected `arg['job'] to be an int."); } job = STDVALUE_AS_INT(*tmp); @@ -173,16 +173,16 @@ static int on_raster_pdf(struct platch_obj *object, FlutterPlatformMessageRespon free(pages); return platch_respond( - responseHandle, + response_handle, &(struct platch_obj){ .codec = kStandardMethodCallResponse, .success = true, .std_result = { .type = kStdTrue } } ); } -static int on_printing_info(struct platch_obj *object, FlutterPlatformMessageResponseHandle *responseHandle) { +static int on_printing_info(struct platch_obj *object, FlutterPlatformMessageResponseHandle *response_handle) { (void) object; return platch_respond( - responseHandle, + response_handle, &PLATCH_OBJ_STD_MSG(STDMAP6( STDSTRING("canPrint"), STDBOOL(false), @@ -200,19 +200,19 @@ static int on_printing_info(struct platch_obj *object, FlutterPlatformMessageRes ); } -static int on_receive(char *channel, struct platch_obj *object, FlutterPlatformMessageResponseHandle *responseHandle) { +static int on_receive(char *channel, struct platch_obj *object, FlutterPlatformMessageResponseHandle *response_handle) { (void) channel; const char *method; method = object->method; if (streq(method, "printingInfo")) { - return on_printing_info(object, responseHandle); + return on_printing_info(object, response_handle); } else if (streq(method, "rasterPdf")) { - return on_raster_pdf(object, responseHandle); + return on_raster_pdf(object, response_handle); } - return platch_respond_not_implemented(responseHandle); + return platch_respond_not_implemented(response_handle); } enum plugin_init_result printing_init(struct flutterpi *flutterpi, void **userdata_out) { From dbad253056c20cb031ee678fc3606ea00bfa3ef1 Mon Sep 17 00:00:00 2001 From: Bozhidar Tonchev Date: Mon, 23 Oct 2023 13:40:42 +0300 Subject: [PATCH 12/12] Remove some logs --- src/plugins/printing.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/plugins/printing.c b/src/plugins/printing.c index 10ac2e54..b5e205c6 100644 --- a/src/plugins/printing.c +++ b/src/plugins/printing.c @@ -127,7 +127,6 @@ static int on_raster_pdf(struct platch_obj *object, FlutterPlatformMessageRespon tmp = stdmap_get_str(&object->std_arg, "doc"); if (tmp == NULL || (*tmp).type != kStdUInt8Array ) { - LOG_ERROR("Call missing mandatory parameter doc.\n"); return platch_respond_illegal_arg_std(response_handle, "Expected `arg['doc'] to be a uint8_t list."); } @@ -153,7 +152,6 @@ static int on_raster_pdf(struct platch_obj *object, FlutterPlatformMessageRespon tmp = stdmap_get_str(&object->std_arg, "scale"); if (tmp == NULL || !STDVALUE_IS_FLOAT(*tmp)) { - LOG_ERROR("Call missing mandatory parameter scale.\n"); return platch_respond_illegal_arg_std(response_handle, "Expected `arg['scale'] to be a double."); } @@ -161,7 +159,6 @@ static int on_raster_pdf(struct platch_obj *object, FlutterPlatformMessageRespon tmp = stdmap_get_str(&object->std_arg, "job"); if (tmp == NULL || !STDVALUE_IS_INT(*tmp)) { - LOG_ERROR("Call missing mandatory parameter job.\n"); return platch_respond_illegal_arg_std(response_handle, "Expected `arg['job'] to be an int."); }