/* sane - Scanner Access Now Easy. Copyright (C) 2019 Touboul Nathane Copyright (C) 2019 Thierry HUCHARD 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 #include #include #if(defined HAVE_LIBPNG) #include #endif #include #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