kopia lustrzana https://gitlab.com/sane-project/backends
				
				
				
			Merge branch 'add-format-pdf' into 'master'
Add format pdf. See merge request sane-project/backends!648release-1.1.x
						commit
						66f2673d71
					
				|  | @ -16,7 +16,7 @@ endif | |||
| 
 | ||||
| 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 \
 | ||||
|                   $(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 "stiff.h" | ||||
| 
 | ||||
| #ifdef HAVE_LIBJPEG | ||||
| #include "jpegtopdf.h" | ||||
| #endif | ||||
| 
 | ||||
| #include "../include/md5.h" | ||||
| 
 | ||||
| #ifndef PATH_MAX | ||||
|  | @ -119,6 +123,7 @@ static struct option basic_options[] = { | |||
| #define OUTPUT_TIFF     2 | ||||
| #define OUTPUT_PNG      3 | ||||
| #define OUTPUT_JPEG     4 | ||||
| #define OUTPUT_PDF      5 | ||||
| 
 | ||||
| #define BASE_OPTSTRING	"d:hi:Lf:o:B::nvVTAbp" | ||||
| #define STRIP_HEIGHT	256	/* # lines we increment image height */ | ||||
|  | @ -1331,7 +1336,7 @@ advance (Image * image) | |||
| } | ||||
| 
 | ||||
| static SANE_Status | ||||
| scan_it (FILE *ofp) | ||||
| scan_it (FILE *ofp, void* pw) | ||||
| { | ||||
|   int i, len, first_frame = 1, offset = 0, must_buffer = 0; | ||||
|   uint64_t hundred_percent = 0; | ||||
|  | @ -1357,6 +1362,8 @@ scan_it (FILE *ofp) | |||
|   struct jpeg_error_mgr jerr; | ||||
| #endif | ||||
| 
 | ||||
|   (void)pw; | ||||
| 
 | ||||
|   do | ||||
|     { | ||||
|       if (!first_frame) | ||||
|  | @ -1451,6 +1458,14 @@ scan_it (FILE *ofp) | |||
| 		    break; | ||||
| #endif | ||||
| #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: | ||||
| 		    write_jpeg_header (parm.format, parm.pixels_per_line, | ||||
| 				       parm.lines, resolution_value, | ||||
|  | @ -1468,7 +1483,7 @@ scan_it (FILE *ofp) | |||
| 	    pngbuf = malloc(parm.bytes_per_line); | ||||
| #endif | ||||
| #ifdef HAVE_LIBJPEG | ||||
| 	  if(output_format == OUTPUT_JPEG) | ||||
| 	  if(output_format == OUTPUT_JPEG || output_format == OUTPUT_PDF) | ||||
| 	    jpegbuf = malloc(parm.bytes_per_line); | ||||
| #endif | ||||
| 
 | ||||
|  | @ -1632,7 +1647,7 @@ scan_it (FILE *ofp) | |||
| 	      else | ||||
| #endif | ||||
| #ifdef HAVE_LIBJPEG | ||||
| 	      if (output_format == OUTPUT_JPEG) | ||||
| 	      if (output_format == OUTPUT_JPEG || output_format == OUTPUT_PDF) | ||||
| 	        { | ||||
| 		  int i = 0; | ||||
| 		  int left = len; | ||||
|  | @ -1732,6 +1747,14 @@ scan_it (FILE *ofp) | |||
|       break; | ||||
| #endif | ||||
| #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: | ||||
| 	write_jpeg_header (parm.format, parm.pixels_per_line, | ||||
| 			   parm.lines, resolution_value, | ||||
|  | @ -1763,7 +1786,7 @@ scan_it (FILE *ofp) | |||
| 	png_write_end(png_ptr, info_ptr); | ||||
| #endif | ||||
| #ifdef HAVE_LIBJPEG | ||||
|     if(output_format == OUTPUT_JPEG) | ||||
|     if(output_format == OUTPUT_JPEG || output_format == OUTPUT_PDF) | ||||
| 	jpeg_finish_compress(&cinfo); | ||||
| #endif | ||||
| 
 | ||||
|  | @ -1778,7 +1801,7 @@ cleanup: | |||
|   } | ||||
| #endif | ||||
| #ifdef HAVE_LIBJPEG | ||||
|   if(output_format == OUTPUT_JPEG) { | ||||
|   if(output_format == OUTPUT_JPEG || output_format == OUTPUT_PDF) { | ||||
|     jpeg_destroy_compress(&cinfo); | ||||
|     free(jpegbuf); | ||||
|   } | ||||
|  | @ -2020,7 +2043,8 @@ static int guess_output_format(const char* output_file) | |||
|         { ".jpg", OUTPUT_JPEG }, | ||||
|         { ".jpeg", OUTPUT_JPEG }, | ||||
|         { ".tiff", OUTPUT_TIFF }, | ||||
|         { ".tif", OUTPUT_TIFF } | ||||
|         { ".tif", OUTPUT_TIFF }, | ||||
|         { ".pdf", OUTPUT_PDF } | ||||
|       }; | ||||
|       for (unsigned i = 0; i < sizeof(formats) / sizeof(formats[0]); ++i) | ||||
|         { | ||||
|  | @ -2055,6 +2079,7 @@ main (int argc, char **argv) | |||
|   SANE_Status status; | ||||
|   char *full_optstring; | ||||
|   SANE_Int version_code; | ||||
|   void *pw = NULL; | ||||
|   FILE *ofp = NULL; | ||||
| 
 | ||||
|   buffer_size = (32 * 1024);	/* default size */ | ||||
|  | @ -2156,6 +2181,15 @@ main (int argc, char **argv) | |||
| #else | ||||
| 	      fprintf(stderr, "JPEG support not compiled in\n"); | ||||
| 	      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 | ||||
| 	    } | ||||
|           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\ | ||||
| -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|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); | ||||
|       printf ("\
 | ||||
| -L, --list-devices         show available scanner devices\n\ | ||||
|  | @ -2625,6 +2659,9 @@ List of available devices:", prog_name); | |||
| 	    break; | ||||
| #endif | ||||
| #ifdef HAVE_LIBJPEG | ||||
| 	  case OUTPUT_PDF: | ||||
| 	    format = "out%d.pdf"; | ||||
| 	    break; | ||||
| 	  case OUTPUT_JPEG: | ||||
| 	    format = "out%d.jpg"; | ||||
| 	    break; | ||||
|  | @ -2645,6 +2682,13 @@ List of available devices:", prog_name); | |||
|                   scanimage_exit(1); | ||||
|                 } | ||||
|             } | ||||
| #ifdef HAVE_LIBJPEG | ||||
|          if (output_format == OUTPUT_PDF) | ||||
|            { | ||||
|              sane_pdf_open(&pw, ofp ); | ||||
|              sane_pdf_start_doc( pw ); | ||||
|            } | ||||
| #endif | ||||
|         } | ||||
| 
 | ||||
|       if (batch) | ||||
|  | @ -2670,11 +2714,14 @@ List of available devices:", prog_name); | |||
| 	{ | ||||
| 	  char 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++) */ | ||||
| 	      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) | ||||
| 			{ | ||||
| #ifdef HAVE_LIBJPEG | ||||
| 	                  if (output_format == OUTPUT_PDF) | ||||
| 			    { | ||||
| 		              sane_pdf_end_doc( pw ); | ||||
| 			      sane_pdf_close ( pw ); | ||||
| 			    } | ||||
| #endif | ||||
| 			  fclose (ofp); | ||||
| 			  ofp = NULL; | ||||
| 			} | ||||
|  | @ -2714,8 +2768,15 @@ List of available devices:", prog_name); | |||
| 	    { | ||||
| 	      fprintf (stderr, "%s: sane_start: %s\n", | ||||
| 		       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); | ||||
| 		  ofp = NULL; | ||||
| 		} | ||||
|  | @ -2726,15 +2787,42 @@ List of available devices:", prog_name); | |||
| 	  /* write to .part file while scanning is in progress */ | ||||
| 	  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); | ||||
| 		  sane_cancel (device); | ||||
| 		  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) | ||||
| 	    { | ||||
| 	      fprintf (stderr, "Scanned page %d.", n); | ||||
|  | @ -2748,32 +2836,47 @@ List of available devices:", prog_name); | |||
| 	      status = SANE_STATUS_GOOD; | ||||
| 	      if (batch) | ||||
| 		{ | ||||
| 		  if (!ofp || 0 != fclose(ofp)) | ||||
| #ifdef HAVE_LIBJPEG | ||||
| 	          if (output_format != OUTPUT_PDF) | ||||
| 		    { | ||||
| 		      fprintf (stderr, "cannot close image file\n"); | ||||
| 		      sane_cancel (device); | ||||
| 		      return SANE_STATUS_ACCESS_DENIED; | ||||
| 		    } | ||||
| 		  else | ||||
| 		    { | ||||
| 		      ofp = NULL; | ||||
| 		      /* let the fully scanned file show up */ | ||||
| 		      if (rename (part_path, path)) | ||||
| 			{ | ||||
| 			  fprintf (stderr, "cannot rename %s to %s\n", | ||||
| 				part_path, path); | ||||
| 			  sane_cancel (device); | ||||
| 			  return SANE_STATUS_ACCESS_DENIED; | ||||
| 			} | ||||
| 		      if (batch_print) | ||||
| 			{ | ||||
| 			  fprintf (stdout, "%s\n", path); | ||||
| 			  fflush (stdout); | ||||
| 			} | ||||
| #endif | ||||
| 		      if (!ofp || 0 != fclose(ofp)) | ||||
| 		        { | ||||
| 		           fprintf (stderr, "cannot close image file\n"); | ||||
| 		           sane_cancel (device); | ||||
| 		           return SANE_STATUS_ACCESS_DENIED; | ||||
| 		        } | ||||
| 		      else | ||||
| 		        { | ||||
| 		           ofp = NULL; | ||||
| 		           /* let the fully scanned file show up */ | ||||
| 		           if (rename (part_path, path)) | ||||
| 		             { | ||||
| 		               fprintf (stderr, "cannot rename %s to %s\n", | ||||
| 		                        part_path, path); | ||||
| 			       sane_cancel (device); | ||||
| 			       return SANE_STATUS_ACCESS_DENIED; | ||||
| 			     } | ||||
| 		           if (batch_print) | ||||
| 			     { | ||||
| 			        fprintf (stdout, "%s\n", path); | ||||
| 			        fflush (stdout); | ||||
| 			     } | ||||
| 		        } | ||||
| #ifdef HAVE_LIBJPEG | ||||
| 		    } | ||||
| #endif | ||||
| 		} | ||||
|               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) | ||||
|                     { | ||||
|                       fclose(ofp); | ||||
|  | @ -2786,13 +2889,20 @@ List of available devices:", prog_name); | |||
| 		{ | ||||
| 		  if (ofp) | ||||
| 		    { | ||||
| 		      fclose (ofp); | ||||
| 		      ofp = NULL; | ||||
| 		    } | ||||
| 		          fclose (ofp); | ||||
| 		          ofp = NULL; | ||||
| 			} | ||||
| 		  unlink (part_path); | ||||
| 		} | ||||
|               else | ||||
|                 { | ||||
| #ifdef HAVE_LIBJPEG | ||||
|                   if (output_format == OUTPUT_PDF) | ||||
|                     { | ||||
|                        sane_pdf_end_doc( pw ); | ||||
|                        sane_pdf_close ( pw ); | ||||
|                     } | ||||
| #endif | ||||
|                   if (output_file && ofp) | ||||
|                     { | ||||
|                       fclose(ofp); | ||||
|  | @ -2810,6 +2920,19 @@ List of available devices:", prog_name); | |||
| 
 | ||||
|       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; | ||||
| 	  fprintf (stderr, "Batch terminated, %d page%s scanned\n", | ||||
| 		   num_pgs, num_pgs == 1 ? "" : "s"); | ||||
|  |  | |||
		Ładowanie…
	
		Reference in New Issue
	
	 Ordissimo
						Ordissimo