kopia lustrzana https://gitlab.com/sane-project/backends
Add format pdf.
rodzic
55ac7b3060
commit
d25f5db739
|
@ -16,7 +16,7 @@ endif
|
||||||
|
|
||||||
AM_CPPFLAGS += -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_srcdir)/include
|
AM_CPPFLAGS += -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_srcdir)/include
|
||||||
|
|
||||||
scanimage_SOURCES = scanimage.c sicc.c sicc.h stiff.c stiff.h
|
scanimage_SOURCES = scanimage.c jpegtopdf.c jpegtopdf.h sicc.c sicc.h stiff.c stiff.h
|
||||||
scanimage_LDADD = ../backend/libsane.la ../sanei/libsanei.la ../lib/liblib.la \
|
scanimage_LDADD = ../backend/libsane.la ../sanei/libsanei.la ../lib/liblib.la \
|
||||||
$(PNG_LIBS) $(JPEG_LIBS)
|
$(PNG_LIBS) $(JPEG_LIBS)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,709 @@
|
||||||
|
/* scanimage -- command line scanning utility
|
||||||
|
* Uses the SANE library.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Thierry HUCHARD <thierry@ordissimo.com>
|
||||||
|
*
|
||||||
|
* For questions and comments contact the sane-devel mailinglist (see
|
||||||
|
* http://www.sane-project.org/mailing-lists.html).
|
||||||
|
*
|
||||||
|
* This program 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 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "jpegtopdf.h"
|
||||||
|
|
||||||
|
#ifndef PATH_MAX
|
||||||
|
# define PATH_MAX 4096
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SANE_NO_ERR (0)
|
||||||
|
#define SANE_NO_ERR_CANCLED (1)
|
||||||
|
|
||||||
|
#define SANE_ERR (-128)
|
||||||
|
#define SANE_FILE_ERR (-1)
|
||||||
|
|
||||||
|
|
||||||
|
/* Creater/Producer */
|
||||||
|
#define SANE_PDF_CREATER "sane"
|
||||||
|
#define SANE_PDF_PRODUCER "sane"
|
||||||
|
|
||||||
|
/* PDF File Header */
|
||||||
|
#define SANE_PDF_HEADER "%%PDF-1.3\n"
|
||||||
|
|
||||||
|
/* trailer format */
|
||||||
|
#define SANE_PDF_TRAILER_OBJ "trailer\n<<\n/Size %d\n/Root 1 0 R\n/Info 3 0 R\n>>\nstartxref\n%lld\n%%%%EOF\n"
|
||||||
|
|
||||||
|
/* xref format */
|
||||||
|
#define SANE_PDF_XREF_OBJ1 "xref\n0 %d\n0000000000 65535 f \n"
|
||||||
|
#define SANE_PDF_XREF_OBJ2 "%010lld 00000 n \n"
|
||||||
|
|
||||||
|
/* Catalog format */
|
||||||
|
#define SANE_PDF_CATALOG_OBJ "1 0 obj\n<<\n/Type /Catalog\n/Pages 2 0 R\n>>\nendobj\n"
|
||||||
|
|
||||||
|
/* Pages format */
|
||||||
|
#define SANE_PDF_PAGES_OBJ1 "2 0 obj\n<<\n/Type /Pages\n/Kids [ "
|
||||||
|
#define SANE_PDF_PAGES_OBJ2 "%d 0 R "
|
||||||
|
#define SANE_PDF_PAGES_OBJ3 "]\n/Count %d\n>>\nendobj\n"
|
||||||
|
|
||||||
|
/* Info format */
|
||||||
|
#define SANE_PDF_INFO_OBJ "3 0 obj\n<<\n/Creator (" SANE_PDF_CREATER ")\n/Producer (" SANE_PDF_PRODUCER ")\n/CreationDate %s\n>>\nendobj\n"
|
||||||
|
#define SANE_PDF_INFO_DATES "(D:%4d%02d%02d%02d%02d%02d%c%02d'%02d')"
|
||||||
|
|
||||||
|
/* Page format */
|
||||||
|
#define SANE_PDF_PAGE_OBJ1 "%d 0 obj\n<<\n/Type /Page\n/Parent 2 0 R\n"
|
||||||
|
#define SANE_PDF_PAGE_OBJ2 "/Resources\n<<\n/XObject << /Im%d %d 0 R >>\n/ProcSet [ /PDF /%s ]\n>>\n"
|
||||||
|
#define SANE_PDF_PAGE_OBJ3 "/MediaBox [ 0 0 %d %d ]\n/Contents %d 0 R\n>>\nendobj\n"
|
||||||
|
#define SANE_PDF_PAGE_OBJ3_180 "/Rotate 180\n/MediaBox [ 0 0 %d %d ]\n/Contents %d 0 R\n>>\nendobj\n"
|
||||||
|
#define SANE_PDF_PAGE_OBJ SANE_PDF_PAGE_OBJ1 SANE_PDF_PAGE_OBJ2 SANE_PDF_PAGE_OBJ3
|
||||||
|
#define SANE_PDF_PAGE_OBJ_180 SANE_PDF_PAGE_OBJ1 SANE_PDF_PAGE_OBJ2 SANE_PDF_PAGE_OBJ3_180
|
||||||
|
|
||||||
|
/* Contents format */
|
||||||
|
#define SANE_PDF_CONTENTS_OBJ1 "%d 0 obj\n<< /Length %d 0 R >>\nstream\n"
|
||||||
|
#define SANE_PDF_CONTENTS_OBJ2 "q\n%d 0 0 %d 0 0 cm\n/Im%d Do\nQ\n"
|
||||||
|
|
||||||
|
/* XObject(Image) format */
|
||||||
|
#define SANE_PDF_IMAGE_OBJ1 "%d 0 obj\n<<\n/Length %d 0 R\n/Type /XObject\n/Subtype /Image\n"
|
||||||
|
#define SANE_PDF_IMAGE_OBJ2 "/Width %d /Height %d\n/ColorSpace /%s\n/BitsPerComponent %d\n"
|
||||||
|
#define SANE_PDF_IMAGE_OBJ3 "/Filter /DCTDecode\n>>\nstream\n"
|
||||||
|
#define SANE_PDF_IMAGE_OBJ SANE_PDF_IMAGE_OBJ1 SANE_PDF_IMAGE_OBJ2 SANE_PDF_IMAGE_OBJ3
|
||||||
|
|
||||||
|
/* Length format */
|
||||||
|
#define SANE_PDF_LENGTH_OBJ "%d 0 obj\n%d\nendobj\n"
|
||||||
|
|
||||||
|
/* end of stream/object */
|
||||||
|
#define SANE_PDF_END_ST_OBJ "endstream\nendobj\n"
|
||||||
|
|
||||||
|
|
||||||
|
/* object id of first page */
|
||||||
|
#define SANE_PDF_FIRST_PAGE_ID (4)
|
||||||
|
|
||||||
|
/* xref max value */
|
||||||
|
#define SANE_PDF_XREF_MAX (9999999999LL)
|
||||||
|
|
||||||
|
/* pdfwork->offset_table */
|
||||||
|
enum {
|
||||||
|
SANE_PDF_ENDDOC_XREF = 0,
|
||||||
|
SANE_PDF_ENDDOC_CATALOG,
|
||||||
|
SANE_PDF_ENDDOC_PAGES,
|
||||||
|
SANE_PDF_ENDDOC_INFO,
|
||||||
|
SANE_PDF_ENDDOC_NUM,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* pdfpage->offset_table */
|
||||||
|
enum {
|
||||||
|
SANE_PDF_PAGE_OBJ_PAGE = 0,
|
||||||
|
SANE_PDF_PAGE_OBJ_IMAGE,
|
||||||
|
SANE_PDF_PAGE_OBJ_IMAGE_LEN,
|
||||||
|
SANE_PDF_PAGE_OBJ_CONTENTS,
|
||||||
|
SANE_PDF_PAGE_OBJ_CONTENTS_LEN,
|
||||||
|
SANE_PDF_PAGE_OBJ_NUM,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Page object info */
|
||||||
|
typedef struct sane_pdf_page {
|
||||||
|
SANE_Int page; /* page No. */
|
||||||
|
SANE_Int obj_id; /* Page object id */
|
||||||
|
SANE_Int image_type; /* ColorSpace, BitsPerComponent */
|
||||||
|
SANE_Int res; /* image resolution */
|
||||||
|
SANE_Int w; /* width (image res) */
|
||||||
|
SANE_Int h; /* height (image res) */
|
||||||
|
SANE_Int w_72; /* width (72dpi) */
|
||||||
|
SANE_Int h_72; /* height (72dpi) */
|
||||||
|
SANE_Int64 offset_table[SANE_PDF_PAGE_OBJ_NUM]; /* xref table */
|
||||||
|
SANE_Int stream_len; /* stream object length */
|
||||||
|
SANE_Int status; /* page object status */
|
||||||
|
struct sane_pdf_page *prev; /* previous page data */
|
||||||
|
struct sane_pdf_page *next; /* next page data */
|
||||||
|
} SANE_pdf_page;
|
||||||
|
|
||||||
|
|
||||||
|
/* PDF Work */
|
||||||
|
typedef struct {
|
||||||
|
SANE_Int obj_num; /* xref - num, trailer - Size */
|
||||||
|
SANE_Int page_num; /* Pages - Count */
|
||||||
|
SANE_Int64 offset_table[SANE_PDF_ENDDOC_NUM]; /* xref table */
|
||||||
|
SANE_pdf_page *first; /* first page data */
|
||||||
|
SANE_pdf_page *last; /* last page data */
|
||||||
|
FILE* fd; /* destination file */
|
||||||
|
} SANE_pdf_work;
|
||||||
|
|
||||||
|
static SANE_Int re_write_if_fail(
|
||||||
|
FILE * fd,
|
||||||
|
void * lpSrc,
|
||||||
|
SANE_Int writeSize )
|
||||||
|
{
|
||||||
|
SANE_Int ret = SANE_ERR, ldata_1st, ldata_2nd;
|
||||||
|
|
||||||
|
if( ( fd == NULL ) || ( lpSrc == NULL ) || ( writeSize <= 0 ) ) {
|
||||||
|
fprintf ( stderr, "[re_write_if_fail]Parameter is error.\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
else if( ( ldata_1st = fwrite( (SANE_Byte *)lpSrc, 1, writeSize, fd ) ) != writeSize ){
|
||||||
|
fprintf ( stderr, "[re_write_if_fail]Can't write file(1st request:%d -> write:%d).\n", writeSize, ldata_1st );
|
||||||
|
if( ( ldata_2nd = fwrite( (SANE_Byte*)lpSrc+ldata_1st, 1, writeSize-ldata_1st, fd) ) != writeSize-ldata_1st ){ /* For detect write() error */
|
||||||
|
fprintf ( stderr, "[re_write_if_fail]Can't write file(2nd request:%d -> write:%d).\n", writeSize-ldata_1st, ldata_2nd );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = SANE_NO_ERR;
|
||||||
|
EXIT:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SANE_Int64 _get_current_offset( FILE *fd )
|
||||||
|
{
|
||||||
|
SANE_Int64 offset64 = (SANE_Int64)fseek( fd, 0, SEEK_CUR );
|
||||||
|
|
||||||
|
if ( offset64 > SANE_PDF_XREF_MAX ) offset64 = -1;
|
||||||
|
|
||||||
|
return offset64;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SANE_Int _get_current_time( struct tm *pt, SANE_Byte *sign_c, int *ptz_h, int *ptz_m )
|
||||||
|
{
|
||||||
|
SANE_Int ret = SANE_ERR;
|
||||||
|
time_t t;
|
||||||
|
long tz;
|
||||||
|
|
||||||
|
if ( pt == NULL || sign_c == NULL || ptz_h == NULL || ptz_m == NULL ) {
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset ((void *)pt, 0, sizeof(struct tm) );
|
||||||
|
/* get time */
|
||||||
|
if( ( t = time( NULL ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " Can't get time.\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
/* get localtime */
|
||||||
|
if ( localtime_r( &t, pt ) == NULL ) {
|
||||||
|
fprintf ( stderr, " Can't get localtime.\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
/* get time difference ( OHH'mm' ) */
|
||||||
|
tz = timezone;
|
||||||
|
if ( tz > 0 ) {
|
||||||
|
*sign_c = '-';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tz = -tz;
|
||||||
|
*sign_c = '+';
|
||||||
|
}
|
||||||
|
*ptz_h = tz / 60 / 60;
|
||||||
|
*ptz_m = ( tz / 60 ) % 60;
|
||||||
|
|
||||||
|
ret = SANE_NO_ERR;
|
||||||
|
EXIT:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
SANE_Int sane_pdf_open( void **ppw, FILE *fd )
|
||||||
|
{
|
||||||
|
SANE_Int ret = SANE_ERR;
|
||||||
|
SANE_pdf_work *p = NULL;
|
||||||
|
|
||||||
|
if ( fd == NULL ) {
|
||||||
|
fprintf ( stderr, " Initialize parameter is error!\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
else if ( ( p = (SANE_pdf_work *)calloc(1, sizeof(SANE_pdf_page) ) ) == NULL ) {
|
||||||
|
fprintf ( stderr, " Can't get work memory!\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->fd = fd;
|
||||||
|
p->obj_num = SANE_PDF_FIRST_PAGE_ID - 1; /* Catalog, Pages, Info */
|
||||||
|
p->page_num = 0;
|
||||||
|
p->first = NULL;
|
||||||
|
p->last = NULL;
|
||||||
|
|
||||||
|
*ppw = (void *)p;
|
||||||
|
|
||||||
|
ret = SANE_NO_ERR;
|
||||||
|
EXIT:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sane_pdf_close( void *pw )
|
||||||
|
{
|
||||||
|
SANE_pdf_page *cur, *next;
|
||||||
|
SANE_pdf_work *pwork = (SANE_pdf_work *)pw;
|
||||||
|
|
||||||
|
if ( pwork == NULL ) {
|
||||||
|
fprintf ( stderr, " Initialize parameter is error!\n");
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = pwork->first;
|
||||||
|
while ( cur != NULL ) {
|
||||||
|
next = cur->next;
|
||||||
|
free( (void *)cur );
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
free ( (void *)pwork );
|
||||||
|
|
||||||
|
EXIT:
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
SANE_Int sane_pdf_start_doc( void *pw )
|
||||||
|
{
|
||||||
|
SANE_Int ret = SANE_ERR, ldata;
|
||||||
|
SANE_Byte str[32];
|
||||||
|
SANE_Int len;
|
||||||
|
SANE_pdf_work *pwork = (SANE_pdf_work *)pw;
|
||||||
|
|
||||||
|
if ( pwork == NULL ) {
|
||||||
|
fprintf ( stderr, " Initialize parameter is error!\n");
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = snprintf( (char*)str, sizeof(str), SANE_PDF_HEADER );
|
||||||
|
if ( (size_t)len >= sizeof(str) || len < 0 ) {
|
||||||
|
fprintf ( stderr, " string is too long!\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
if ( ( ldata = re_write_if_fail( pwork->fd, str, len ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " Error is occured in re_write_if_fail.\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = SANE_NO_ERR;
|
||||||
|
EXIT:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
SANE_Int sane_pdf_end_doc( void *pw )
|
||||||
|
{
|
||||||
|
SANE_Int ret = SANE_ERR, ldata, i, size, w_count;
|
||||||
|
SANE_pdf_page *p = NULL;
|
||||||
|
SANE_Byte str[1024], str_t[64];
|
||||||
|
SANE_Int len;
|
||||||
|
SANE_pdf_work *pwork = (SANE_pdf_work *)pw;
|
||||||
|
|
||||||
|
struct tm tm;
|
||||||
|
SANE_Byte sign_c;
|
||||||
|
int tz_h = 0, tz_m = 0;
|
||||||
|
|
||||||
|
if ( pwork == NULL ) {
|
||||||
|
fprintf ( stderr, " Initialize parameter is error!\n");
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = pwork->obj_num + 1;
|
||||||
|
w_count = 1;
|
||||||
|
|
||||||
|
/* <1> Pages */
|
||||||
|
if ( ( pwork->offset_table[ SANE_PDF_ENDDOC_PAGES ] = _get_current_offset( pwork->fd ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " offset > %lld\n", SANE_PDF_XREF_MAX );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
/* write Pages(1) */
|
||||||
|
len = snprintf( (char*)str, sizeof(str), SANE_PDF_PAGES_OBJ1 );
|
||||||
|
if ( (size_t)len >= sizeof(str) || len < 0 ) {
|
||||||
|
fprintf ( stderr, " string is too long!\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
if ( ( ldata = re_write_if_fail( pwork->fd, str, len ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " Error is occured in re_write_if_fail.\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write Pages(2) ... Kids array */
|
||||||
|
p = pwork->first;
|
||||||
|
i = 0;
|
||||||
|
while ( p != NULL ) {
|
||||||
|
i++;
|
||||||
|
if ( p->status != SANE_NO_ERR ) {
|
||||||
|
fprintf ( stderr, " page(%d) is NG!\n", i );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = snprintf( (char*)str, sizeof(str), SANE_PDF_PAGES_OBJ2, (int)p->obj_id ); /* Page object id */
|
||||||
|
if ( (size_t)len >= sizeof(str) || len < 0 ) {
|
||||||
|
fprintf ( stderr, " string is too long!\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
if ( ( ldata = re_write_if_fail( pwork->fd, str, len ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " Error is occured in re_write_if_fail.\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write Pages(3) */
|
||||||
|
len = snprintf( (char*)str, sizeof(str), SANE_PDF_PAGES_OBJ3, (int)pwork->page_num ); /* Count */
|
||||||
|
if ( (size_t)len >= sizeof(str) || len < 0 ) {
|
||||||
|
fprintf ( stderr, " string is too long!\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
if ( ( ldata = re_write_if_fail( pwork->fd, str, len ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " Error is occured in re_write_if_fail.\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* <2> Catalog */
|
||||||
|
if ( ( pwork->offset_table[ SANE_PDF_ENDDOC_CATALOG ] = _get_current_offset( pwork->fd ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " offset > %lld\n", SANE_PDF_XREF_MAX );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
/* write Catalog */
|
||||||
|
len = snprintf( (char*)str, sizeof(str), SANE_PDF_CATALOG_OBJ );
|
||||||
|
if ( (size_t)len >= sizeof(str) || len < 0 ) {
|
||||||
|
fprintf ( stderr, " string is too long!\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
if ( ( ldata = re_write_if_fail( pwork->fd, str, len ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " Error is occured in re_write_if_fail.\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* <3> Info */
|
||||||
|
if ( ( pwork->offset_table[ SANE_PDF_ENDDOC_INFO ] = _get_current_offset( pwork->fd ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " offset > %lld\n", SANE_PDF_XREF_MAX );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
if ( _get_current_time( &tm, &sign_c, &tz_h, &tz_m ) == SANE_ERR ) {
|
||||||
|
fprintf ( stderr, " Error is occured in _get_current_time.\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
/* Dates format */
|
||||||
|
len = snprintf((char*)str_t, sizeof(str_t), SANE_PDF_INFO_DATES,
|
||||||
|
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
||||||
|
tm.tm_hour, tm.tm_min, tm.tm_sec, sign_c, tz_h, tz_m );
|
||||||
|
if ( (size_t)len >= sizeof(str_t) || len < 0 ) {
|
||||||
|
fprintf ( stderr, " string is too long!\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
/* write Info */
|
||||||
|
len = snprintf( (char*)str, sizeof(str), SANE_PDF_INFO_OBJ, str_t ); /* CreationDate */
|
||||||
|
if ( (size_t)len >= sizeof(str) || len < 0 ) {
|
||||||
|
fprintf ( stderr, " string is too long!\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
if ( ( ldata = re_write_if_fail( pwork->fd, str, len ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " Error is occured in re_write_if_fail.\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* <4> xref */
|
||||||
|
if ( ( pwork->offset_table[ SANE_PDF_ENDDOC_XREF ] = _get_current_offset( pwork->fd ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " offset > %lld\n", SANE_PDF_XREF_MAX );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
/* write xref(1) */
|
||||||
|
len = snprintf( (char*)str, sizeof(str), SANE_PDF_XREF_OBJ1, (int)size ); /* object num */
|
||||||
|
if ( (size_t)len >= sizeof(str) || len < 0 ) {
|
||||||
|
fprintf ( stderr, " string is too long!\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
if ( ( ldata = re_write_if_fail( pwork->fd, str, len ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " Error is occured in re_write_if_fail.\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write xref(2) */
|
||||||
|
len = snprintf( (char*)str, sizeof(str), SANE_PDF_XREF_OBJ2 SANE_PDF_XREF_OBJ2 SANE_PDF_XREF_OBJ2,
|
||||||
|
pwork->offset_table[ SANE_PDF_ENDDOC_CATALOG ], /* object id = 1 : Catalog */
|
||||||
|
pwork->offset_table[ SANE_PDF_ENDDOC_PAGES ], /* object id = 2 : Pages */
|
||||||
|
pwork->offset_table[ SANE_PDF_ENDDOC_INFO ] ); /* object id = 3 : Info */
|
||||||
|
if ( (size_t)len >= sizeof(str) || len < 0 ) {
|
||||||
|
fprintf ( stderr, " string is too long!\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
if ( ( ldata = re_write_if_fail( pwork->fd, str, len ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " Error is occured in re_write_if_fail.\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
w_count += SANE_PDF_FIRST_PAGE_ID - 1;
|
||||||
|
|
||||||
|
/* write xref(3) */
|
||||||
|
p = pwork->first;
|
||||||
|
while ( p != NULL ) {
|
||||||
|
/* write offset : SANE_PDF_PAGE_OBJ_PAGE -> SANE_PDF_PAGE_OBJ_CONTENTS_LEN */
|
||||||
|
for ( i = 0; i < SANE_PDF_PAGE_OBJ_NUM; i++ ) {
|
||||||
|
len = snprintf( (char*)str, sizeof(str), SANE_PDF_XREF_OBJ2, p->offset_table[ i ] ); /* object id = 3 ~ */
|
||||||
|
if ( (size_t)len >= sizeof(str) || len < 0 ) {
|
||||||
|
fprintf ( stderr, " string is too long!\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
if ( ( ldata = re_write_if_fail( pwork->fd, str, len ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " Error is occured in re_write_if_fail.\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
w_count ++;
|
||||||
|
}
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
/* check object number */
|
||||||
|
if ( w_count != size ) {
|
||||||
|
fprintf ( stderr, " object number is wrong.\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* <4> trailer */
|
||||||
|
len = snprintf( (char*)str, sizeof(str), SANE_PDF_TRAILER_OBJ,
|
||||||
|
(int)size, /* object num */
|
||||||
|
pwork->offset_table[ SANE_PDF_ENDDOC_XREF ] ); /* xref offset */
|
||||||
|
if ( (size_t)len >= sizeof(str) || len < 0 ) {
|
||||||
|
fprintf ( stderr, " string is too long!\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
if ( ( ldata = re_write_if_fail( pwork->fd, str, len ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " Error is occured in re_write_if_fail.\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ret = SANE_NO_ERR;
|
||||||
|
EXIT:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
SANE_Int sane_pdf_start_page(
|
||||||
|
void *pw,
|
||||||
|
SANE_Int w,
|
||||||
|
SANE_Int h,
|
||||||
|
SANE_Int res,
|
||||||
|
SANE_Int type,
|
||||||
|
SANE_Int rotate )
|
||||||
|
{
|
||||||
|
SANE_Int ret = SANE_ERR, ldata;
|
||||||
|
SANE_pdf_page *p = NULL;
|
||||||
|
SANE_Byte str[1024];
|
||||||
|
SANE_Int len, len_c;
|
||||||
|
SANE_Byte *ProcSetImage[SANE_PDF_IMAGE_NUM] = { (SANE_Byte *)"ImageC", (SANE_Byte *)"ImageG", (SANE_Byte *)"ImageG" };
|
||||||
|
SANE_Byte *ColorSpace[SANE_PDF_IMAGE_NUM] = { (SANE_Byte *)"DeviceRGB", (SANE_Byte *)"DeviceGray", (SANE_Byte *)"DeviceGray" };
|
||||||
|
SANE_Int BitsPerComponent[SANE_PDF_IMAGE_NUM] = { 8, 8, 1 };
|
||||||
|
SANE_pdf_work *pwork = (SANE_pdf_work *)pw;
|
||||||
|
|
||||||
|
if ( pwork == NULL || w <= 0 || h <= 0 || res <= 0 ||
|
||||||
|
!( type == SANE_PDF_IMAGE_COLOR || type == SANE_PDF_IMAGE_GRAY || type == SANE_PDF_IMAGE_MONO ) ||
|
||||||
|
!( rotate == SANE_PDF_ROTATE_OFF || rotate == SANE_PDF_ROTATE_ON ) ) {
|
||||||
|
fprintf ( stderr, " Initialize parameter is error!\n");
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
else if ( ( p = (SANE_pdf_page *)calloc( 1, sizeof(SANE_pdf_page) ) ) == NULL ) {
|
||||||
|
fprintf ( stderr, " Can't get work memory!\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
pwork->obj_num += SANE_PDF_PAGE_OBJ_NUM;
|
||||||
|
pwork->page_num ++;
|
||||||
|
|
||||||
|
p->prev = p->next = NULL;
|
||||||
|
if ( pwork->first == NULL ) {
|
||||||
|
/* append first page */
|
||||||
|
pwork->first = p;
|
||||||
|
}
|
||||||
|
if ( pwork->last == NULL ) {
|
||||||
|
/* append first page */
|
||||||
|
pwork->last = p;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* append page */
|
||||||
|
pwork->last->next = p;
|
||||||
|
p->prev = pwork->last;
|
||||||
|
pwork->last = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->page = pwork->page_num;
|
||||||
|
/* page obj id : page1=4, page2=4+5=9, page3=4+5*2=14, ... */
|
||||||
|
p->obj_id = SANE_PDF_FIRST_PAGE_ID + ( p->page - 1 ) * SANE_PDF_PAGE_OBJ_NUM;
|
||||||
|
p->image_type = type;
|
||||||
|
p->res = res;
|
||||||
|
p->w = w; p->h = h;
|
||||||
|
p->w_72 = w * 72 / res; p->h_72 = h * 72 / res;
|
||||||
|
p->stream_len = 0;
|
||||||
|
p->status = SANE_ERR;
|
||||||
|
|
||||||
|
/* <1> Page */
|
||||||
|
if ( ( p->offset_table[ SANE_PDF_PAGE_OBJ_PAGE ] = _get_current_offset( pwork->fd ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " offset > %lld\n", SANE_PDF_XREF_MAX );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
/* write Page */
|
||||||
|
if ( rotate == SANE_PDF_ROTATE_OFF ) {
|
||||||
|
len = snprintf( (char*)str, sizeof(str), SANE_PDF_PAGE_OBJ,
|
||||||
|
(int)(p->obj_id + SANE_PDF_PAGE_OBJ_PAGE), /* object id ( Page ) */
|
||||||
|
(int)p->page, /* ImX (X = page number) ... XObject/Image Name */
|
||||||
|
(int)(p->obj_id + SANE_PDF_PAGE_OBJ_IMAGE), /* object id ( XObject/Image ) */
|
||||||
|
ProcSetImage[ type ], /* ProcSet */
|
||||||
|
(int)p->w_72, (int)p->h_72, /* MediaBox */
|
||||||
|
(int)(p->obj_id + SANE_PDF_PAGE_OBJ_CONTENTS) ); /* object id ( Contents ) */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
len = snprintf( (char*)str, sizeof(str), SANE_PDF_PAGE_OBJ_180,
|
||||||
|
(int)(p->obj_id + SANE_PDF_PAGE_OBJ_PAGE), /* object id ( Page ) */
|
||||||
|
(int)p->page, /* ImX (X = page number) ... XObject/Image Name */
|
||||||
|
(int)(p->obj_id + SANE_PDF_PAGE_OBJ_IMAGE), /* object id ( XObject/Image ) */
|
||||||
|
ProcSetImage[ type ], /* ProcSet */
|
||||||
|
(int)p->w_72, (int)p->h_72, /* MediaBox */
|
||||||
|
(int)(p->obj_id + SANE_PDF_PAGE_OBJ_CONTENTS) ); /* object id ( Contents ) */
|
||||||
|
}
|
||||||
|
if ( (size_t)len >= sizeof(str) || len < 0 ) {
|
||||||
|
fprintf ( stderr, " string is too long!\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
if ( ( ldata = re_write_if_fail( pwork->fd, str, len ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " Error is occured in re_write_if_fail.\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* <2> Contents */
|
||||||
|
if ( ( p->offset_table[ SANE_PDF_PAGE_OBJ_CONTENTS ] = _get_current_offset( pwork->fd ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " offset > %lld\n", SANE_PDF_XREF_MAX );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
/* write Contents(1) */
|
||||||
|
len = snprintf( (char*)str, sizeof(str), SANE_PDF_CONTENTS_OBJ1,
|
||||||
|
(int)(p->obj_id + SANE_PDF_PAGE_OBJ_CONTENTS), /* object id ( Contents ) */
|
||||||
|
(int)(p->obj_id + SANE_PDF_PAGE_OBJ_CONTENTS_LEN) ); /* object id ( Length of Contents ) */
|
||||||
|
if ( (size_t)len >= sizeof(str) || len < 0 ) {
|
||||||
|
fprintf ( stderr, " string is too long!\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
if ( ( ldata = re_write_if_fail( pwork->fd, str, len ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " Error is occured in re_write_if_fail.\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
/* write Contents(2) */
|
||||||
|
len_c = len = snprintf( (char*)str, sizeof(str), SANE_PDF_CONTENTS_OBJ2,
|
||||||
|
(int)p->w_72, (int)p->h_72, /* CTM ( scaling ) */
|
||||||
|
(int)p->page ); /* ImX (X = page number) ... XObject/Image Name */
|
||||||
|
if ( (size_t)len >= sizeof(str) || len < 0 ) {
|
||||||
|
fprintf ( stderr, " string is too long!\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
if ( ( ldata = re_write_if_fail( pwork->fd, str, len ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " Error is occured in re_write_if_fail.\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write Contents(3) */
|
||||||
|
len = snprintf( (char*)str, sizeof(str), SANE_PDF_END_ST_OBJ );
|
||||||
|
if ( (size_t)len >= sizeof(str) || len < 0 ) {
|
||||||
|
fprintf ( stderr, " string is too long!\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
if ( ( ldata = re_write_if_fail( pwork->fd, str, len ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " Error is occured in re_write_if_fail.\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* <3> Length of Contents - stream */
|
||||||
|
if ( ( p->offset_table[ SANE_PDF_PAGE_OBJ_CONTENTS_LEN ] = _get_current_offset( pwork->fd ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " offset > %lld\n", SANE_PDF_XREF_MAX );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
/* write Length */
|
||||||
|
len = snprintf( (char *)str, sizeof(str), SANE_PDF_LENGTH_OBJ,
|
||||||
|
(int)(p->obj_id + SANE_PDF_PAGE_OBJ_CONTENTS_LEN), /* object id ( Length of Contents ) */
|
||||||
|
len_c ); /* length value */
|
||||||
|
if ( (size_t)len >= sizeof(str) || len < 0 ) {
|
||||||
|
fprintf ( stderr, " string is too long!\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
if ( ( ldata = re_write_if_fail( pwork->fd, str, len ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " Error is occured in re_write_if_fail.\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* <4> XObject(Image) */
|
||||||
|
if ( ( p->offset_table[ SANE_PDF_PAGE_OBJ_IMAGE ] = _get_current_offset( pwork->fd ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " offset > %lld\n", SANE_PDF_XREF_MAX );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
/* write XObject */
|
||||||
|
len = snprintf( (char*)str, sizeof(str), SANE_PDF_IMAGE_OBJ,
|
||||||
|
(int)(p->obj_id + SANE_PDF_PAGE_OBJ_IMAGE), /* object id ( XObject(Image) ) */
|
||||||
|
(int)(p->obj_id + SANE_PDF_PAGE_OBJ_IMAGE_LEN), /* object id ( Length of XObject ) */
|
||||||
|
(int)p->w, (int)p->h, /* Width/Height */
|
||||||
|
ColorSpace[ type ], /* ColorSpace */
|
||||||
|
(int)BitsPerComponent[ type ] ); /* BitsPerComponent */
|
||||||
|
if ( (size_t)len >= sizeof(str) || len < 0 ) {
|
||||||
|
fprintf ( stderr, " string is too long!\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
if ( ( ldata = re_write_if_fail( pwork->fd, str, len ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " Error is occured in re_write_if_fail.\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = SANE_NO_ERR;
|
||||||
|
EXIT:
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SANE_Int sane_pdf_end_page( void *pw )
|
||||||
|
{
|
||||||
|
SANE_Int ret = SANE_ERR, ldata;
|
||||||
|
SANE_pdf_page *p = NULL;
|
||||||
|
SANE_Byte str[1024];
|
||||||
|
SANE_Int len;
|
||||||
|
SANE_pdf_work *pwork = (SANE_pdf_work *)pw;
|
||||||
|
|
||||||
|
if ( pwork == NULL ) {
|
||||||
|
fprintf ( stderr, " Initialize parameter is error!\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = pwork->last;
|
||||||
|
|
||||||
|
/* <1> endstream, endobj (XObject) */
|
||||||
|
len = snprintf( (char*)str, sizeof(str), SANE_PDF_END_ST_OBJ );
|
||||||
|
if ( (size_t)len >= sizeof(str) || len < 0 ) {
|
||||||
|
fprintf ( stderr, " string is too long!\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
if ( ( ldata = re_write_if_fail( pwork->fd, str, len ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " Error is occured in re_write_if_fail.\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* <2> Length of XObject - stream */
|
||||||
|
if ( ( p->offset_table[ SANE_PDF_PAGE_OBJ_IMAGE_LEN ] = _get_current_offset( pwork->fd ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " offset > %lld\n", SANE_PDF_XREF_MAX );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
/* write Length */
|
||||||
|
len = snprintf( (char*)str, sizeof(str), SANE_PDF_LENGTH_OBJ,
|
||||||
|
(int)(p->obj_id + SANE_PDF_PAGE_OBJ_IMAGE_LEN), /* object id ( Length of XObject stream ) */
|
||||||
|
(int)p->stream_len ); /* length value */
|
||||||
|
if ( (size_t)len >= sizeof(str) || len < 0 ) {
|
||||||
|
fprintf ( stderr, " string is too long!\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
if ( ( ldata = re_write_if_fail( pwork->fd, str, len ) ) < 0 ) {
|
||||||
|
fprintf ( stderr, " Error is occured in re_write_if_fail.\n" );
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = SANE_NO_ERR;
|
||||||
|
p->status = SANE_NO_ERR;
|
||||||
|
EXIT:
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
/* scanimage -- command line scanning utility
|
||||||
|
* Uses the SANE library.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Thierry HUCHARD <thierry@ordissimo.com>
|
||||||
|
*
|
||||||
|
* For questions and comments contact the sane-devel mailinglist (see
|
||||||
|
* http://www.sane-project.org/mailing-lists.html).
|
||||||
|
*
|
||||||
|
* This program 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 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __JPEG_TO_PDF_H__
|
||||||
|
#define __JPEG_TO_PDF_H__
|
||||||
|
|
||||||
|
#include "../include/_stdint.h"
|
||||||
|
|
||||||
|
#include "../include/sane/sane.h"
|
||||||
|
#include "../include/sane/sanei.h"
|
||||||
|
#include "../include/sane/saneopts.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef PATH_MAX
|
||||||
|
# define PATH_MAX 4096
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef long long SANE_Int64;
|
||||||
|
|
||||||
|
/* sane_pdf_StartPage - type */
|
||||||
|
enum {
|
||||||
|
SANE_PDF_IMAGE_COLOR = 0, /* RGB24bit */
|
||||||
|
SANE_PDF_IMAGE_GRAY, /* Gray8bit */
|
||||||
|
SANE_PDF_IMAGE_MONO, /* Gray1bit */
|
||||||
|
SANE_PDF_IMAGE_NUM,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* sane_pdf_StartPage - rotate */
|
||||||
|
enum {
|
||||||
|
SANE_PDF_ROTATE_OFF = 0, /* rotate off */
|
||||||
|
SANE_PDF_ROTATE_ON, /* rotate 180 degrees */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct mynode
|
||||||
|
{
|
||||||
|
SANE_Int page;
|
||||||
|
SANE_Int show_page;
|
||||||
|
SANE_Int rotate;
|
||||||
|
struct mynode *prev;
|
||||||
|
struct mynode *next;
|
||||||
|
FILE* fd;
|
||||||
|
SANE_Int file_size;
|
||||||
|
SANE_Byte file_path[ PATH_MAX ];
|
||||||
|
} SANE_PDF_NODE, *LPSANE_PDF_NODE;
|
||||||
|
|
||||||
|
|
||||||
|
SANE_Int sane_pdf_open( void **ppw, FILE* fd );
|
||||||
|
void sane_pdf_close( void *pw );
|
||||||
|
|
||||||
|
SANE_Int sane_pdf_start_doc( void *pw );
|
||||||
|
SANE_Int sane_pdf_end_doc( void *pw );
|
||||||
|
|
||||||
|
SANE_Int sane_pdf_start_page( void *pw, SANE_Int w, SANE_Int h, SANE_Int res, SANE_Int type, SANE_Int rotate );
|
||||||
|
SANE_Int sane_pdf_end_page( void *pw );
|
||||||
|
|
||||||
|
#endif /* __JPEG_TO_PDF_H__ */
|
|
@ -60,6 +60,10 @@
|
||||||
#include "sicc.h"
|
#include "sicc.h"
|
||||||
#include "stiff.h"
|
#include "stiff.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBJPEG
|
||||||
|
#include "jpegtopdf.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "../include/md5.h"
|
#include "../include/md5.h"
|
||||||
|
|
||||||
#ifndef PATH_MAX
|
#ifndef PATH_MAX
|
||||||
|
@ -119,6 +123,7 @@ static struct option basic_options[] = {
|
||||||
#define OUTPUT_TIFF 2
|
#define OUTPUT_TIFF 2
|
||||||
#define OUTPUT_PNG 3
|
#define OUTPUT_PNG 3
|
||||||
#define OUTPUT_JPEG 4
|
#define OUTPUT_JPEG 4
|
||||||
|
#define OUTPUT_PDF 5
|
||||||
|
|
||||||
#define BASE_OPTSTRING "d:hi:Lf:o:B::nvVTAbp"
|
#define BASE_OPTSTRING "d:hi:Lf:o:B::nvVTAbp"
|
||||||
#define STRIP_HEIGHT 256 /* # lines we increment image height */
|
#define STRIP_HEIGHT 256 /* # lines we increment image height */
|
||||||
|
@ -1331,7 +1336,7 @@ advance (Image * image)
|
||||||
}
|
}
|
||||||
|
|
||||||
static SANE_Status
|
static SANE_Status
|
||||||
scan_it (FILE *ofp)
|
scan_it (FILE *ofp, void* pw)
|
||||||
{
|
{
|
||||||
int i, len, first_frame = 1, offset = 0, must_buffer = 0;
|
int i, len, first_frame = 1, offset = 0, must_buffer = 0;
|
||||||
uint64_t hundred_percent = 0;
|
uint64_t hundred_percent = 0;
|
||||||
|
@ -1357,6 +1362,8 @@ scan_it (FILE *ofp)
|
||||||
struct jpeg_error_mgr jerr;
|
struct jpeg_error_mgr jerr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
(void)pw;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (!first_frame)
|
if (!first_frame)
|
||||||
|
@ -1451,6 +1458,14 @@ scan_it (FILE *ofp)
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_LIBJPEG
|
#ifdef HAVE_LIBJPEG
|
||||||
|
case OUTPUT_PDF:
|
||||||
|
sane_pdf_start_page ( pw, parm.pixels_per_line, parm.lines,
|
||||||
|
resolution_value, SANE_PDF_IMAGE_COLOR,
|
||||||
|
SANE_PDF_ROTATE_OFF);
|
||||||
|
write_jpeg_header (parm.format, parm.pixels_per_line,
|
||||||
|
parm.lines, resolution_value,
|
||||||
|
ofp, &cinfo, &jerr);
|
||||||
|
break;
|
||||||
case OUTPUT_JPEG:
|
case OUTPUT_JPEG:
|
||||||
write_jpeg_header (parm.format, parm.pixels_per_line,
|
write_jpeg_header (parm.format, parm.pixels_per_line,
|
||||||
parm.lines, resolution_value,
|
parm.lines, resolution_value,
|
||||||
|
@ -1468,7 +1483,7 @@ scan_it (FILE *ofp)
|
||||||
pngbuf = malloc(parm.bytes_per_line);
|
pngbuf = malloc(parm.bytes_per_line);
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_LIBJPEG
|
#ifdef HAVE_LIBJPEG
|
||||||
if(output_format == OUTPUT_JPEG)
|
if(output_format == OUTPUT_JPEG || output_format == OUTPUT_PDF)
|
||||||
jpegbuf = malloc(parm.bytes_per_line);
|
jpegbuf = malloc(parm.bytes_per_line);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1632,7 +1647,7 @@ scan_it (FILE *ofp)
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_LIBJPEG
|
#ifdef HAVE_LIBJPEG
|
||||||
if (output_format == OUTPUT_JPEG)
|
if (output_format == OUTPUT_JPEG || output_format == OUTPUT_PDF)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int left = len;
|
int left = len;
|
||||||
|
@ -1732,6 +1747,14 @@ scan_it (FILE *ofp)
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_LIBJPEG
|
#ifdef HAVE_LIBJPEG
|
||||||
|
case OUTPUT_PDF:
|
||||||
|
sane_pdf_start_page ( pw, parm.pixels_per_line, parm.lines,
|
||||||
|
resolution_value, SANE_PDF_IMAGE_COLOR,
|
||||||
|
SANE_PDF_ROTATE_OFF);
|
||||||
|
write_jpeg_header (parm.format, parm.pixels_per_line,
|
||||||
|
parm.lines, resolution_value,
|
||||||
|
ofp, &cinfo, &jerr);
|
||||||
|
break;
|
||||||
case OUTPUT_JPEG:
|
case OUTPUT_JPEG:
|
||||||
write_jpeg_header (parm.format, parm.pixels_per_line,
|
write_jpeg_header (parm.format, parm.pixels_per_line,
|
||||||
parm.lines, resolution_value,
|
parm.lines, resolution_value,
|
||||||
|
@ -1763,7 +1786,7 @@ scan_it (FILE *ofp)
|
||||||
png_write_end(png_ptr, info_ptr);
|
png_write_end(png_ptr, info_ptr);
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_LIBJPEG
|
#ifdef HAVE_LIBJPEG
|
||||||
if(output_format == OUTPUT_JPEG)
|
if(output_format == OUTPUT_JPEG || output_format == OUTPUT_PDF)
|
||||||
jpeg_finish_compress(&cinfo);
|
jpeg_finish_compress(&cinfo);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1778,7 +1801,7 @@ cleanup:
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_LIBJPEG
|
#ifdef HAVE_LIBJPEG
|
||||||
if(output_format == OUTPUT_JPEG) {
|
if(output_format == OUTPUT_JPEG || output_format == OUTPUT_PDF) {
|
||||||
jpeg_destroy_compress(&cinfo);
|
jpeg_destroy_compress(&cinfo);
|
||||||
free(jpegbuf);
|
free(jpegbuf);
|
||||||
}
|
}
|
||||||
|
@ -2020,7 +2043,8 @@ static int guess_output_format(const char* output_file)
|
||||||
{ ".jpg", OUTPUT_JPEG },
|
{ ".jpg", OUTPUT_JPEG },
|
||||||
{ ".jpeg", OUTPUT_JPEG },
|
{ ".jpeg", OUTPUT_JPEG },
|
||||||
{ ".tiff", OUTPUT_TIFF },
|
{ ".tiff", OUTPUT_TIFF },
|
||||||
{ ".tif", OUTPUT_TIFF }
|
{ ".tif", OUTPUT_TIFF },
|
||||||
|
{ ".pdf", OUTPUT_PDF }
|
||||||
};
|
};
|
||||||
for (unsigned i = 0; i < sizeof(formats) / sizeof(formats[0]); ++i)
|
for (unsigned i = 0; i < sizeof(formats) / sizeof(formats[0]); ++i)
|
||||||
{
|
{
|
||||||
|
@ -2055,6 +2079,7 @@ main (int argc, char **argv)
|
||||||
SANE_Status status;
|
SANE_Status status;
|
||||||
char *full_optstring;
|
char *full_optstring;
|
||||||
SANE_Int version_code;
|
SANE_Int version_code;
|
||||||
|
void *pw = NULL;
|
||||||
FILE *ofp = NULL;
|
FILE *ofp = NULL;
|
||||||
|
|
||||||
buffer_size = (32 * 1024); /* default size */
|
buffer_size = (32 * 1024); /* default size */
|
||||||
|
@ -2156,6 +2181,15 @@ main (int argc, char **argv)
|
||||||
#else
|
#else
|
||||||
fprintf(stderr, "JPEG support not compiled in\n");
|
fprintf(stderr, "JPEG support not compiled in\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (strcmp (optarg, "pdf") == 0)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_LIBJPEG
|
||||||
|
output_format = OUTPUT_PDF;
|
||||||
|
#else
|
||||||
|
fprintf(stderr, "PDF support not compiled in\n");
|
||||||
|
exit(1);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if (strcmp (optarg, "pnm") == 0)
|
else if (strcmp (optarg, "pnm") == 0)
|
||||||
|
@ -2311,7 +2345,7 @@ standard output.\n\
|
||||||
Parameters are separated by a blank from single-character options (e.g.\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 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\
|
-d, --device-name=DEVICE use a given scanner device (e.g. hp:/dev/scanner)\n\
|
||||||
--format=pnm|tiff|png|jpeg file format of output file\n\
|
--format=pnm|tiff|png|jpeg|pdf file format of output file\n\
|
||||||
-i, --icc-profile=PROFILE include this ICC profile into TIFF file\n", prog_name);
|
-i, --icc-profile=PROFILE include this ICC profile into TIFF file\n", prog_name);
|
||||||
printf ("\
|
printf ("\
|
||||||
-L, --list-devices show available scanner devices\n\
|
-L, --list-devices show available scanner devices\n\
|
||||||
|
@ -2625,6 +2659,9 @@ List of available devices:", prog_name);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_LIBJPEG
|
#ifdef HAVE_LIBJPEG
|
||||||
|
case OUTPUT_PDF:
|
||||||
|
format = "out%d.pdf";
|
||||||
|
break;
|
||||||
case OUTPUT_JPEG:
|
case OUTPUT_JPEG:
|
||||||
format = "out%d.jpg";
|
format = "out%d.jpg";
|
||||||
break;
|
break;
|
||||||
|
@ -2645,6 +2682,13 @@ List of available devices:", prog_name);
|
||||||
scanimage_exit(1);
|
scanimage_exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef HAVE_LIBJPEG
|
||||||
|
if (output_format == OUTPUT_PDF)
|
||||||
|
{
|
||||||
|
sane_pdf_open(&pw, ofp );
|
||||||
|
sane_pdf_start_doc( pw );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (batch)
|
if (batch)
|
||||||
|
@ -2670,11 +2714,14 @@ List of available devices:", prog_name);
|
||||||
{
|
{
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
char part_path[PATH_MAX];
|
char part_path[PATH_MAX];
|
||||||
if (batch) /* format is NULL unless batch mode */
|
if (batch) /* format is NULL unless batch mode */
|
||||||
{
|
{
|
||||||
sprintf (path, format, n); /* love --(C++) */
|
sprintf (path, format, n); /* love --(C++) */
|
||||||
strcpy (part_path, path);
|
strcpy (part_path, path);
|
||||||
strcat (part_path, ".part");
|
#ifdef HAVE_LIBJPEG
|
||||||
|
if (output_format != OUTPUT_PDF)
|
||||||
|
#endif
|
||||||
|
strcat (part_path, ".part");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2692,6 +2739,13 @@ List of available devices:", prog_name);
|
||||||
{
|
{
|
||||||
if (ofp)
|
if (ofp)
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_LIBJPEG
|
||||||
|
if (output_format == OUTPUT_PDF)
|
||||||
|
{
|
||||||
|
sane_pdf_end_doc( pw );
|
||||||
|
sane_pdf_close ( pw );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
fclose (ofp);
|
fclose (ofp);
|
||||||
ofp = NULL;
|
ofp = NULL;
|
||||||
}
|
}
|
||||||
|
@ -2714,8 +2768,15 @@ List of available devices:", prog_name);
|
||||||
{
|
{
|
||||||
fprintf (stderr, "%s: sane_start: %s\n",
|
fprintf (stderr, "%s: sane_start: %s\n",
|
||||||
prog_name, sane_strstatus (status));
|
prog_name, sane_strstatus (status));
|
||||||
if (ofp)
|
if (ofp )
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_LIBJPEG
|
||||||
|
if (output_format == OUTPUT_PDF)
|
||||||
|
{
|
||||||
|
sane_pdf_end_doc( pw );
|
||||||
|
sane_pdf_close ( pw );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
fclose (ofp);
|
fclose (ofp);
|
||||||
ofp = NULL;
|
ofp = NULL;
|
||||||
}
|
}
|
||||||
|
@ -2726,15 +2787,42 @@ List of available devices:", prog_name);
|
||||||
/* write to .part file while scanning is in progress */
|
/* write to .part file while scanning is in progress */
|
||||||
if (batch)
|
if (batch)
|
||||||
{
|
{
|
||||||
if (NULL == (ofp = fopen (part_path, "w")))
|
#ifdef HAVE_LIBJPEG
|
||||||
|
SANE_Bool init_pdf = SANE_FALSE;
|
||||||
|
#endif
|
||||||
|
if (ofp == NULL)
|
||||||
|
{
|
||||||
|
ofp = fopen (part_path, "w");
|
||||||
|
#ifdef HAVE_LIBJPEG
|
||||||
|
if (output_format == OUTPUT_PDF && ofp != NULL)
|
||||||
|
init_pdf = SANE_TRUE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (NULL == ofp)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "cannot open %s\n", part_path);
|
fprintf (stderr, "cannot open %s\n", part_path);
|
||||||
sane_cancel (device);
|
sane_cancel (device);
|
||||||
return SANE_STATUS_ACCESS_DENIED;
|
return SANE_STATUS_ACCESS_DENIED;
|
||||||
}
|
}
|
||||||
|
#ifdef HAVE_LIBJPEG
|
||||||
|
if (init_pdf )
|
||||||
|
{
|
||||||
|
sane_pdf_open( &pw, ofp );
|
||||||
|
sane_pdf_start_doc ( pw );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
status = scan_it (ofp);
|
status = scan_it (ofp, pw);
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBJPEG
|
||||||
|
if (output_format == OUTPUT_PDF)
|
||||||
|
{
|
||||||
|
sane_pdf_end_page( pw );
|
||||||
|
fflush( ofp );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (batch)
|
if (batch)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "Scanned page %d.", n);
|
fprintf (stderr, "Scanned page %d.", n);
|
||||||
|
@ -2748,32 +2836,47 @@ List of available devices:", prog_name);
|
||||||
status = SANE_STATUS_GOOD;
|
status = SANE_STATUS_GOOD;
|
||||||
if (batch)
|
if (batch)
|
||||||
{
|
{
|
||||||
if (!ofp || 0 != fclose(ofp))
|
#ifdef HAVE_LIBJPEG
|
||||||
|
if (output_format != OUTPUT_PDF)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "cannot close image file\n");
|
#endif
|
||||||
sane_cancel (device);
|
if (!ofp || 0 != fclose(ofp))
|
||||||
return SANE_STATUS_ACCESS_DENIED;
|
{
|
||||||
}
|
fprintf (stderr, "cannot close image file\n");
|
||||||
else
|
sane_cancel (device);
|
||||||
{
|
return SANE_STATUS_ACCESS_DENIED;
|
||||||
ofp = NULL;
|
}
|
||||||
/* let the fully scanned file show up */
|
else
|
||||||
if (rename (part_path, path))
|
{
|
||||||
{
|
ofp = NULL;
|
||||||
fprintf (stderr, "cannot rename %s to %s\n",
|
/* let the fully scanned file show up */
|
||||||
part_path, path);
|
if (rename (part_path, path))
|
||||||
sane_cancel (device);
|
{
|
||||||
return SANE_STATUS_ACCESS_DENIED;
|
fprintf (stderr, "cannot rename %s to %s\n",
|
||||||
}
|
part_path, path);
|
||||||
if (batch_print)
|
sane_cancel (device);
|
||||||
{
|
return SANE_STATUS_ACCESS_DENIED;
|
||||||
fprintf (stdout, "%s\n", path);
|
}
|
||||||
fflush (stdout);
|
if (batch_print)
|
||||||
}
|
{
|
||||||
|
fprintf (stdout, "%s\n", path);
|
||||||
|
fflush (stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef HAVE_LIBJPEG
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_LIBJPEG
|
||||||
|
if (output_format == OUTPUT_PDF)
|
||||||
|
{
|
||||||
|
sane_pdf_end_doc( pw );
|
||||||
|
fflush( ofp );
|
||||||
|
sane_pdf_close ( pw );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (output_file && ofp)
|
if (output_file && ofp)
|
||||||
{
|
{
|
||||||
fclose(ofp);
|
fclose(ofp);
|
||||||
|
@ -2786,13 +2889,20 @@ List of available devices:", prog_name);
|
||||||
{
|
{
|
||||||
if (ofp)
|
if (ofp)
|
||||||
{
|
{
|
||||||
fclose (ofp);
|
fclose (ofp);
|
||||||
ofp = NULL;
|
ofp = NULL;
|
||||||
}
|
}
|
||||||
unlink (part_path);
|
unlink (part_path);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_LIBJPEG
|
||||||
|
if (output_format == OUTPUT_PDF)
|
||||||
|
{
|
||||||
|
sane_pdf_end_doc( pw );
|
||||||
|
sane_pdf_close ( pw );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (output_file && ofp)
|
if (output_file && ofp)
|
||||||
{
|
{
|
||||||
fclose(ofp);
|
fclose(ofp);
|
||||||
|
@ -2810,6 +2920,19 @@ List of available devices:", prog_name);
|
||||||
|
|
||||||
if (batch)
|
if (batch)
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_LIBJPEG
|
||||||
|
if (output_format == OUTPUT_PDF)
|
||||||
|
{
|
||||||
|
if (output_file && ofp)
|
||||||
|
{
|
||||||
|
sane_pdf_end_doc( pw );
|
||||||
|
fflush( ofp );
|
||||||
|
sane_pdf_close ( pw );
|
||||||
|
fclose(ofp);
|
||||||
|
ofp = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
int num_pgs = (n - batch_start_at) / batch_increment;
|
int num_pgs = (n - batch_start_at) / batch_increment;
|
||||||
fprintf (stderr, "Batch terminated, %d page%s scanned\n",
|
fprintf (stderr, "Batch terminated, %d page%s scanned\n",
|
||||||
num_pgs, num_pgs == 1 ? "" : "s");
|
num_pgs, num_pgs == 1 ? "" : "s");
|
||||||
|
|
Ładowanie…
Reference in New Issue