diff options
Diffstat (limited to 'backend/escl/escl_png.c')
-rw-r--r-- | backend/escl/escl_png.c | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/backend/escl/escl_png.c b/backend/escl/escl_png.c new file mode 100644 index 0000000..18f6f35 --- /dev/null +++ b/backend/escl/escl_png.c @@ -0,0 +1,193 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Touboul Nathane + 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> + +#if(defined HAVE_LIBPNG) +#include <png.h> +#endif + +#include <setjmp.h> + + +#if(defined HAVE_LIBPNG) + +/** + * \fn SANE_Status escl_sane_decompressor(escl_sane_t *handler) + * \brief Function that aims to decompress the png 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_PNG_data(capabilities_t *scanner, int *w, int *h, int *components) +{ + unsigned int width = 0; /* largeur */ + unsigned int height = 0; /* hauteur */ + int bps = 3; /* composantes d'un texel */ + unsigned char *texels = NULL; /* données de l'image */ + unsigned int i = 0; + png_byte magic[8]; + + // read magic number + fread (magic, 1, sizeof (magic), scanner->tmp); + // check for valid magic number + if (!png_check_sig (magic, sizeof (magic))) + { + DBG( 1, "Escl Png : PNG error is not a valid PNG image!\n"); + if (scanner->tmp) { + fclose(scanner->tmp); + scanner->tmp = NULL; + } + return (SANE_STATUS_INVAL); + } + // create a png read struct + png_structp png_ptr = png_create_read_struct + (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) + { + DBG( 1, "Escl Png : PNG error create a png read struct\n"); + if (scanner->tmp) + if (scanner->tmp) { + fclose(scanner->tmp); + scanner->tmp = NULL; + } + return (SANE_STATUS_INVAL); + } + // create a png info struct + png_infop info_ptr = png_create_info_struct (png_ptr); + if (!info_ptr) + { + DBG( 1, "Escl Png : PNG error create a png info struct\n"); + png_destroy_read_struct (&png_ptr, NULL, NULL); + if (scanner->tmp) { + fclose(scanner->tmp); + scanner->tmp = NULL; + } + return (SANE_STATUS_INVAL); + } + // initialize the setjmp for returning properly after a libpng + // error occured + if (setjmp (png_jmpbuf (png_ptr))) + { + png_destroy_read_struct (&png_ptr, &info_ptr, NULL); + if (texels) + free (texels); + fprintf(stderr,"PNG read error.\n"); + if (scanner->tmp) { + fclose(scanner->tmp); + scanner->tmp = NULL; + } + DBG( 1, "Escl Png : PNG read error.\n"); + return (SANE_STATUS_INVAL); + } + // setup libpng for using standard C fread() function + // with our FILE pointer + png_init_io (png_ptr, scanner->tmp); + // tell libpng that we have already read the magic number + png_set_sig_bytes (png_ptr, sizeof (magic)); + + // read png info + png_read_info (png_ptr, info_ptr); + + int bit_depth, color_type; + // get some usefull information from header + bit_depth = png_get_bit_depth (png_ptr, info_ptr); + color_type = png_get_color_type (png_ptr, info_ptr); + // convert index color images to RGB images + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb (png_ptr); + else if (color_type != PNG_COLOR_TYPE_RGB && color_type != PNG_COLOR_TYPE_RGB_ALPHA) + { + fprintf(stderr,"PNG format not supported.\n"); + if (scanner->tmp) { + fclose(scanner->tmp); + scanner->tmp = NULL; + } + return (SANE_STATUS_INVAL); + } + if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bps = 4; + else + bps = 3; + if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_tRNS_to_alpha (png_ptr); + if (bit_depth == 16) + png_set_strip_16 (png_ptr); + else if (bit_depth < 8) + png_set_packing (png_ptr); + // update info structure to apply transformations + png_read_update_info (png_ptr, info_ptr); + // retrieve updated information + png_get_IHDR (png_ptr, info_ptr, + (png_uint_32*)(&width), + (png_uint_32*)(&height), + &bit_depth, &color_type, + NULL, NULL, NULL); + + *w = (int)width; + *h = (int)height; + *components = bps; + // we can now allocate memory for storing pixel data + texels = (unsigned char *)malloc (sizeof (unsigned char) * width + * height * bps); + png_bytep *row_pointers; + // setup a pointer array. Each one points at the begening of a row. + row_pointers = (png_bytep *)malloc (sizeof (png_bytep) * height); + for (i = 0; i < height; ++i) + { + row_pointers[i] = (png_bytep)(texels + + ((height - (i + 1)) * width * bps)); + } + // read pixel data using row pointers + png_read_image (png_ptr, row_pointers); + // we don't need row pointers anymore + scanner->img_data = texels; + scanner->img_size = (int)(width * height * bps); + scanner->img_read = 0; + free (row_pointers); + fclose(scanner->tmp); + scanner->tmp = NULL; + return (SANE_STATUS_GOOD); +} +#else + +SANE_Status +get_PNG_data(capabilities_t __sane_unused__ *scanner, + int __sane_unused__ *w, + int __sane_unused__ *h, + int __sane_unused__ *bps) +{ + return (SANE_STATUS_INVAL); +} + +#endif |