[sane-devel] [PATCH v4 1/2] add PNG format to scanimage
Matteo Croce
matteo at openwrt.org
Fri Sep 18 09:51:02 UTC 2015
---
fix 1 bit scans colors
acinclude.m4 | 13 +++++
configure.in | 1 +
doc/scanimage.man | 4 +-
frontend/Makefile.am | 2 +-
frontend/scanimage.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++----
5 files changed, 155 insertions(+), 14 deletions(-)
diff --git a/acinclude.m4 b/acinclude.m4
index a8f1b7c..41a2ea4 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -312,6 +312,19 @@ AC_DEFUN([SANE_CHECK_TIFF],
AC_SUBST(TIFF_LIBS)
])
+AC_DEFUN([SANE_CHECK_PNG],
+[
+ AC_CHECK_LIB(png,png_init_io,
+ [
+ AC_CHECK_HEADER(png.h,
+ [sane_cv_use_libpng="yes"; PNG_LIBS="-lpng"],)
+ ],)
+ if test "$sane_cv_use_libpng" = "yes" ; then
+ AC_DEFINE(HAVE_LIBPNG,1,[Define to 1 if you have the libpng library.])
+ fi
+ AC_SUBST(PNG_LIBS)
+])
+
#
# Checks for pthread support
AC_DEFUN([SANE_CHECK_LOCKING],
diff --git a/configure.in b/configure.in
index 387c64a..56eb339 100644
--- a/configure.in
+++ b/configure.in
@@ -122,6 +122,7 @@ AC_SUBST(SYSLOG_LIBS)
SANE_CHECK_JPEG
SANE_CHECK_TIFF
+SANE_CHECK_PNG
SANE_CHECK_IEEE1284
SANE_CHECK_PTHREAD
SANE_CHECK_LOCKING
diff --git a/doc/scanimage.man b/doc/scanimage.man
index f726713..387e962 100644
--- a/doc/scanimage.man
+++ b/doc/scanimage.man
@@ -103,9 +103,9 @@ The
option selects how image data is written to standard output.
.I format
can be
-.B pnm
+.B pnm tiff
or
-.BR tiff.
+.BR png.
If
.B \-\-format
is not used, PNM is written.
diff --git a/frontend/Makefile.am b/frontend/Makefile.am
index a501931..5adf22a 100644
--- a/frontend/Makefile.am
+++ b/frontend/Makefile.am
@@ -18,7 +18,7 @@ AM_CPPFLAGS = -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_srcdir)/include
scanimage_SOURCES = scanimage.c stiff.c stiff.h
scanimage_LDADD = ../backend/libsane.la ../sanei/libsanei.la ../lib/liblib.la \
- ../lib/libfelib.la
+ ../lib/libfelib.la @PNG_LIBS@
saned_SOURCES = saned.c
saned_LDADD = ../backend/libsane.la ../sanei/libsanei.la ../lib/liblib.la \
diff --git a/frontend/scanimage.c b/frontend/scanimage.c
index 9a84716..77217b3 100644
--- a/frontend/scanimage.c
+++ b/frontend/scanimage.c
@@ -42,6 +42,10 @@
#include <sys/types.h>
#include <sys/stat.h>
+#ifdef HAVE_LIBPNG
+#include <png.h>
+#endif
+
#include "../include/_stdint.h"
#include "../include/sane/sane.h"
@@ -104,6 +108,7 @@ static struct option basic_options[] = {
#define OUTPUT_PNM 0
#define OUTPUT_TIFF 1
+#define OUTPUT_PNG 2
#define BASE_OPTSTRING "d:hi:Lf:B::nvVTAbp"
#define STRIP_HEIGHT 256 /* # lines we increment image height */
@@ -1153,6 +1158,47 @@ write_pnm_header (SANE_Frame format, int width, int height, int depth, FILE *ofp
#endif
}
+#ifdef HAVE_LIBPNG
+static void
+write_png_header (SANE_Frame format, int width, int height, int depth, FILE *ofp, png_structp* png_ptr, png_infop* info_ptr)
+{
+ int color_type;
+
+ *png_ptr = png_create_write_struct
+ (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!*png_ptr) {
+ fprintf(stderr, "png_create_write_struct failed\n");
+ exit(1);
+ }
+ *info_ptr = png_create_info_struct(*png_ptr);
+ if (!*info_ptr) {
+ fprintf(stderr, "png_create_info_struct failed\n");
+ exit(1);
+ }
+ png_init_io(*png_ptr, ofp);
+
+ switch (format)
+ {
+ case SANE_FRAME_RED:
+ case SANE_FRAME_GREEN:
+ case SANE_FRAME_BLUE:
+ case SANE_FRAME_RGB:
+ color_type = PNG_COLOR_TYPE_RGB;
+ break;
+
+ default:
+ color_type = PNG_COLOR_TYPE_GRAY;
+ break;
+ }
+
+ png_set_IHDR(*png_ptr, *info_ptr, width, height,
+ depth, color_type, PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+ png_write_info(*png_ptr, *info_ptr);
+}
+#endif
+
static void *
advance (Image * image)
{
@@ -1196,6 +1242,12 @@ scan_it (FILE *ofp)
};
SANE_Word total_bytes = 0, expected_bytes;
SANE_Int hang_over = -1;
+#ifdef HAVE_LIBPNG
+ int pngrow = 0;
+ png_bytep pngbuf = NULL;
+ png_structp png_ptr;
+ png_infop info_ptr;
+#endif
do
{
@@ -1269,21 +1321,34 @@ scan_it (FILE *ofp)
offset = 0;
}
else
- {
- if (output_format == OUTPUT_TIFF)
+ switch(output_format)
+ {
+ case OUTPUT_TIFF:
sanei_write_tiff_header (parm.format,
parm.pixels_per_line, parm.lines,
parm.depth, resolution_value,
icc_profile, ofp);
- else
+ break;
+ case OUTPUT_PNM:
write_pnm_header (parm.format, parm.pixels_per_line,
parm.lines, parm.depth, ofp);
- }
+ break;
+#ifdef HAVE_LIBPNG
+ case OUTPUT_PNG:
+ write_png_header (parm.format, parm.pixels_per_line,
+ parm.lines, parm.depth, ofp, &png_ptr, &info_ptr);
+ break;
+#endif
+ }
break;
default:
break;
}
+#ifdef HAVE_LIBPNG
+ if(output_format == OUTPUT_PNG)
+ pngbuf = malloc(parm.bytes_per_line);
+#endif
if (must_buffer)
{
@@ -1397,6 +1462,30 @@ scan_it (FILE *ofp)
}
else /* ! must_buffer */
{
+#ifdef HAVE_LIBPNG
+ if (output_format == OUTPUT_PNG)
+ {
+ int i = 0;
+ int left = len;
+ while(pngrow + left >= parm.bytes_per_line)
+ {
+ memcpy(pngbuf + pngrow, buffer + i, parm.bytes_per_line - pngrow);
+ if(parm.depth == 1)
+ {
+ int j;
+ for(j = 0; j < parm.bytes_per_line; j++)
+ pngbuf[j] = ~pngbuf[j];
+ }
+ png_write_row(png_ptr, pngbuf);
+ i += parm.bytes_per_line - pngrow;
+ left -= parm.bytes_per_line - pngrow;
+ pngrow = 0;
+ }
+ memcpy(pngbuf + pngrow, buffer + i, left);
+ pngrow += left;
+ }
+ else
+#endif
if ((output_format == OUTPUT_TIFF) || (parm.depth != 16))
fwrite (buffer, 1, len, ofp);
else
@@ -1451,13 +1540,23 @@ scan_it (FILE *ofp)
{
image.height = image.y;
- if (output_format == OUTPUT_TIFF)
+ switch(output_format) {
+ case OUTPUT_TIFF:
sanei_write_tiff_header (parm.format, parm.pixels_per_line,
image.height, parm.depth, resolution_value,
icc_profile, ofp);
- else
+ break;
+ case OUTPUT_PNM:
write_pnm_header (parm.format, parm.pixels_per_line,
image.height, parm.depth, ofp);
+ break;
+#ifdef HAVE_LIBPNG
+ case OUTPUT_PNG:
+ write_png_header (parm.format, parm.pixels_per_line,
+ image.height, parm.depth, ofp, &png_ptr, &info_ptr);
+ break;
+#endif
+ }
#if !defined(WORDS_BIGENDIAN)
/* multibyte pnm file may need byte swap to LE */
@@ -1477,11 +1576,21 @@ scan_it (FILE *ofp)
fwrite (image.data, 1, image.height * image.width, ofp);
}
+#ifdef HAVE_LIBPNG
+ if(output_format == OUTPUT_PNG)
+ png_write_end(png_ptr, info_ptr);
+#endif
/* flush the output buffer */
fflush( ofp );
cleanup:
+#ifdef HAVE_LIBPNG
+ if(output_format == OUTPUT_PNG) {
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ free(pngbuf);
+ }
+#endif
if (image.data)
free (image.data);
@@ -1799,6 +1908,15 @@ main (int argc, char **argv)
case OPTION_FORMAT:
if (strcmp (optarg, "tiff") == 0)
output_format = OUTPUT_TIFF;
+ else if (strcmp (optarg, "png") == 0)
+ {
+#ifdef HAVE_LIBPNG
+ output_format = OUTPUT_PNG;
+#else
+ fprintf(stderr, "PNG support not compiled in\n");
+ exit(1);
+#endif
+ }
else
output_format = OUTPUT_PNM;
break;
@@ -1937,7 +2055,7 @@ standard output.\n\
Parameters are separated by a blank from single-character options (e.g.\n\
-d epson) and by a \"=\" from multi-character options (e.g. --device-name=epson).\n\
-d, --device-name=DEVICE use a given scanner device (e.g. hp:/dev/scanner)\n\
- --format=pnm|tiff file format of output file\n\
+ --format=pnm|tiff|png file format of output file\n\
-i, --icc-profile=PROFILE include this ICC profile into TIFF file\n", prog_name);
printf ("\
-L, --list-devices show available scanner devices\n\
@@ -1945,8 +2063,8 @@ Parameters are separated by a blank from single-character options (e.g.\n\
can be specified: %%d (device name), %%v (vendor),\n\
%%m (model), %%t (type), %%i (index number), and\n\
%%n (newline)\n\
--b, --batch[=FORMAT] working in batch mode, FORMAT is `out%%d.pnm' or\n\
- `out%%d.tif' by default depending on --format\n");
+-b, --batch[=FORMAT] working in batch mode, FORMAT is `out%%d.pnm' `out%%d.tif' or\n\
+ `out%%d.png' by default depending on --format\n");
printf ("\
--batch-start=# page number to start naming files with\n\
--batch-count=# how many pages to scan in batch mode\n\
@@ -2225,10 +2343,19 @@ List of available devices:", prog_name);
if (batch && NULL == format)
{
- if (output_format == OUTPUT_TIFF)
+ switch(output_format) {
+ case OUTPUT_TIFF:
format = "out%d.tif";
- else
+ break;
+ case OUTPUT_PNM:
format = "out%d.pnm";
+ break;
+#ifdef HAVE_LIBPNG
+ case OUTPUT_PNG:
+ format = "out%d.png";
+ break;
+#endif
+ }
}
if (!batch)
--
2.1.4
More information about the sane-devel
mailing list