diff options
Diffstat (limited to 'backend/escl/escl_mupdf.c')
-rw-r--r-- | backend/escl/escl_mupdf.c | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/backend/escl/escl_mupdf.c b/backend/escl/escl_mupdf.c new file mode 100644 index 0000000..9399218 --- /dev/null +++ b/backend/escl/escl_mupdf.c @@ -0,0 +1,256 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Thierry HUCHARD <thierry@ordissimo.com> + + This file is part of the SANE package. + + SANE is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + SANE is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with sane; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + This file implements a SANE backend for eSCL scanners. */ + +#define DEBUG_DECLARE_ONLY +#include "../include/sane/config.h" + +#include "escl.h" + +#include "../include/sane/sanei.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <errno.h> + +#if(defined HAVE_MUPDF) +#include <mupdf/fitz.h> +#endif + +#include <setjmp.h> + + +#if(defined HAVE_MUPDF) + +// TODO: WIN32: HANDLE CreateFileW(), etc. +// TODO: POSIX: int creat(), read(), write(), lseeko, etc. + +typedef struct fz_file_stream_escl_s +{ + FILE *file; + unsigned char buffer[4096]; +} fz_file_stream_escl; + +static int +next_file_escl(fz_context *ctx, fz_stream *stm, size_t n) +{ + fz_file_stream_escl *state = stm->state; + + /* n is only a hint, that we can safely ignore */ + n = fread(state->buffer, 1, sizeof(state->buffer), state->file); + if (n < sizeof(state->buffer) && ferror(state->file)) + fz_throw(ctx, FZ_ERROR_GENERIC, "read error: %s", strerror(errno)); + stm->rp = state->buffer; + stm->wp = state->buffer + n; + stm->pos += (int64_t)n; + + if (n == 0) + return EOF; + return *stm->rp++; +} + +static void +drop_file_escl(fz_context *ctx, void *state_) +{ + fz_file_stream_escl *state = state_; + int n = fclose(state->file); + if (n < 0) + fz_warn(ctx, "close error: %s", strerror(errno)); + fz_free(ctx, state); +} + +static void +seek_file_escl(fz_context *ctx, fz_stream *stm, int64_t offset, int whence) +{ + fz_file_stream_escl *state = stm->state; +#ifdef _WIN32 + int64_t n = _fseeki64(state->file, offset, whence); +#else + int64_t n = fseeko(state->file, offset, whence); +#endif + if (n < 0) + fz_throw(ctx, FZ_ERROR_GENERIC, "cannot seek: %s", strerror(errno)); +#ifdef _WIN32 + stm->pos = _ftelli64(state->file); +#else + stm->pos = ftello(state->file); +#endif + stm->rp = state->buffer; + stm->wp = state->buffer; +} + +static fz_stream * +fz_open_file_ptr_escl(fz_context *ctx, FILE *file) +{ + fz_stream *stm; + fz_file_stream_escl *state = fz_malloc_struct(ctx, fz_file_stream_escl); + state->file = file; + + stm = fz_new_stream(ctx, state, next_file_escl, drop_file_escl); + stm->seek = seek_file_escl; + + return stm; +} + +/** + * \fn SANE_Status escl_sane_decompressor(escl_sane_t *handler) + * \brief Function that aims to decompress the pdf image to SANE be able + * to read the image. + * This function is called in the "sane_read" function. + * + * \return SANE_STATUS_GOOD (if everything is OK, otherwise, + * SANE_STATUS_NO_MEM/SANE_STATUS_INVAL) + */ +SANE_Status +get_PDF_data(capabilities_t *scanner, int *width, int *height, int *bps) +{ + int page_number = -1, page_count = -2; + fz_context *ctx; + fz_document *doc; + fz_pixmap *pix; + fz_matrix ctm; + fz_stream *stream; + unsigned char *surface = NULL; /* Image data */ + SANE_Status status = SANE_STATUS_GOOD; + + /* Create a context to hold the exception stack and various caches. */ + ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED); + if (!ctx) + { + DBG(1, "cannot create mupdf context\n"); + status = SANE_STATUS_INVAL; + goto close_file; + } + + /* Register the default file types to handle. */ + fz_try(ctx) + fz_register_document_handlers(ctx); + fz_catch(ctx) + { + DBG(1, "cannot register document handlers: %s\n", fz_caught_message(ctx)); + status = SANE_STATUS_INVAL; + goto drop_context; + } + + /* Open the stream. */ + fz_try(ctx) + stream = fz_open_file_ptr_escl(ctx, scanner->tmp); + fz_catch(ctx) + { + DBG(1, "cannot open stream: %s\n", fz_caught_message(ctx)); + status = SANE_STATUS_INVAL; + goto drop_context; + } + + /* Seek stream. */ + fz_try(ctx) + fz_seek(ctx, stream, 0, SEEK_SET); + fz_catch(ctx) + { + DBG(1, "cannot seek stream: %s\n", fz_caught_message(ctx)); + status = SANE_STATUS_INVAL; + goto drop_stream; + } + + /* Open the document. */ + fz_try(ctx) + doc = fz_open_document_with_stream(ctx, "filename.pdf", stream); + fz_catch(ctx) + { + DBG(1, "cannot open document: %s\n", fz_caught_message(ctx)); + status = SANE_STATUS_INVAL; + goto drop_stream; + } + + /* Count the number of pages. */ + fz_try(ctx) + page_count = fz_count_pages(ctx, doc); + fz_catch(ctx) + { + DBG(1, "cannot count number of pages: %s\n", fz_caught_message(ctx)); + status = SANE_STATUS_INVAL; + goto drop_document; + } + + if (page_number < 0 || page_number >= page_count) + { + DBG(1, "page number out of range: %d (page count %d)\n", page_number + 1, page_count); + status = SANE_STATUS_INVAL; + goto drop_document; + } + + /* Compute a transformation matrix for the zoom and rotation desired. */ + /* The default resolution without scaling is 72 dpi. */ + fz_scale(&ctm, (float)1.0, (float)1.0); + fz_pre_rotate(&ctm, (float)0.0); + + /* Render page to an RGB pixmap. */ + fz_try(ctx) + pix = fz_new_pixmap_from_page_number(ctx, doc, 0, &ctm, fz_device_rgb(ctx), 0); + fz_catch(ctx) + { + DBG(1, "cannot render page: %s\n", fz_caught_message(ctx)); + status = SANE_STATUS_INVAL; + goto drop_document; + } + + surface = malloc(pix->h * pix->stride); + memcpy(surface, pix->samples, (pix->h * pix->stride)); + + // If necessary, trim the image. + surface = escl_crop_surface(scanner, surface, pix->w, pix->h, pix->n, width, height); + if (!surface) { + DBG( 1, "Escl Pdf : Surface Memory allocation problem\n"); + status = SANE_STATUS_NO_MEM; + goto drop_pix; + } + *bps = pix->n; + + /* Clean up. */ +drop_pix: + fz_drop_pixmap(ctx, pix); +drop_document: + fz_drop_document(ctx, doc); +drop_stream: + fz_drop_stream(ctx, stream); +drop_context: + fz_drop_context(ctx); + +close_file: + if (scanner->tmp) + fclose(scanner->tmp); + scanner->tmp = NULL; + return status; +} +#else + +SANE_Status +get_PDF_data(capabilities_t __sane_unused__ *scanner, + int __sane_unused__ *width, + int __sane_unused__ *height, + int __sane_unused__ *bps) +{ + return (SANE_STATUS_INVAL); +} + +#endif |