2 main routine for pdf2swf(1)
4 Part of the swftools package.
6 Copyright (c) 2001,2002,2003 Matthias Kramm <kramm@quiss.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
27 #include <sys/types.h>
29 #include "../config.h"
40 #include "../lib/args.h"
41 #include "../lib/os.h"
42 #include "../lib/rfxswf.h"
43 #include "../lib/devices/swf.h"
44 #include "../lib/devices/polyops.h"
45 #include "../lib/devices/record.h"
46 #include "../lib/devices/rescale.h"
47 #include "../lib/gfxfilter.h"
48 #include "../lib/pdf/pdf.h"
49 #include "../lib/log.h"
51 #define SWFDIR concatPaths(getInstallationPath(), "swfs")
53 static gfxsource_t
*driver
= 0;
54 static gfxdevice_t
*out
= 0;
56 static int maxwidth
=0, maxheight
=0;
58 static char * outputname
= 0;
59 static int loglevel
= 3;
60 static char * pagerange
= 0;
61 static char * filename
= 0;
62 static char * password
= 0;
65 static char * preloader
= 0;
66 static char * viewer
= 0;
70 static int info_only
= 0;
72 static int max_time
= 0;
74 static int flatten
= 0;
76 static char* filters
= 0;
84 int clip_x1
=0,clip_y1
=0,clip_x2
=0,clip_y2
=0;
87 static int system_quiet
=0;
89 int systemf(const char* format
, ...)
94 va_start(arglist
, format
);
95 vsnprintf(buf
, sizeof(buf
)-1, format
, arglist
);
104 fprintf(stderr
, "system() returned %d\n", ret
);
111 void sigalarm(int signal
)
113 msg("<fatal> Aborting rendering after %d seconds", max_time
);
114 #if 0 && defined(HAVE_SYS_TIME_H) && defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRUSAGE)
116 getrusage(RUSAGE_CHILDREN
, &usage
);
117 msg("<fatal> Memory used: %d,%d,%d", usage
.ru_maxrss
, usage
.ru_idrss
, usage
.ru_isrss
);
119 #if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_H)
120 struct mallinfo info
= mallinfo();
121 msg("<fatal> Memory used: %d Mb (%d bytes)", info
.uordblks
/1048576, info
.uordblks
);
127 typedef struct _parameter
{
128 struct _parameter
*next
;
133 static parameter_t
* device_config
= 0;
134 static parameter_t
* device_config_next
= 0;
135 static void store_parameter(const char*name
, const char*value
)
137 parameter_t
*o
= device_config
;
139 if(!strcmp(name
, o
->name
)) {
140 /* overwrite old value */
141 free((void*)o
->value
);
142 o
->value
= strdup(value
);
147 parameter_t
*p
= (parameter_t
*)malloc(sizeof(parameter_t
));
148 p
->name
= strdup(name
);
149 p
->value
= strdup(value
);
152 if(device_config_next
) {
153 device_config_next
->next
= p
;
154 device_config_next
= p
;
157 device_config_next
= p
;
161 int args_callback_option(char*name
,char*val
) {
162 if (!strcmp(name
, "o"))
167 else if (!strcmp(name
, "v"))
170 setConsoleLogging(loglevel
);
173 else if (!strcmp(name
, "2"))
179 else if (!strcmp(name
, "4"))
185 else if (!strcmp(name
, "9"))
191 else if (!strcmp(name
, "X"))
193 maxwidth
= atoi(val
);
196 else if (!strcmp(name
, "Y"))
198 maxheight
= atoi(val
);
201 else if (!strcmp(name
, "q"))
204 setConsoleLogging(loglevel
);
208 else if (name
[0]=='p')
210 /* check whether the page range follows the p directly, like
214 } while(*name
== 32 || *name
== 13 || *name
== 10 || *name
== '\t');
223 else if (!strcmp(name
, "P"))
228 else if (!strcmp(name
, "c"))
230 char*s
= strdup(val
);
231 char*x1
= strtok(s
, ":");
232 char*y1
= strtok(0, ":");
233 char*x2
= strtok(0, ":");
234 char*y2
= strtok(0, ":");
235 if(!(x1
&& y1
&& x2
&& y2
)) {
236 fprintf(stderr
, "-c option requires four arguments, <x1>:<y1>:<x2>:<y2>\n");
247 else if (!strcmp(name
, "m"))
249 char*s
= strdup(val
);
250 char*c
= strchr(s
, ':');
252 fprintf(stderr
, "-m option requires two arguments, <x>:<y>\n");
262 else if (!strcmp(name
, "s"))
265 char*c
= strchr(s
, '=');
266 if(c
&& *c
&& c
[1]) {
269 store_parameter(s
,c
);
270 } else if(!strcmp(s
,"help")) {
271 printf("PDF Parameters:\n");
272 gfxsource_t
*pdf
= gfxsource_pdf_create();
273 pdf
->setparameter(pdf
, "help", "");
275 gfxdevice_swf_init(&swf
);
276 printf("SWF Parameters:\n");
277 swf
.setparameter(&swf
, "help", "");
280 store_parameter(s
,"1");
284 else if (!strcmp(name
, "S"))
286 store_parameter("drawonlyshapes", "1");
289 else if (!strcmp(name
, "i"))
291 store_parameter("ignoredraworder", "1");
295 else if (!strcmp(name
, "Q"))
297 max_time
= atoi(val
);
299 # ifdef HAVE_SIGNAL_H
300 signal(SIGALRM
, sigalarm
);
305 else if (!strcmp(name
, "z"))
307 store_parameter("enablezlib", "1");
311 else if (!strcmp(name
, "n"))
313 store_parameter("opennewwindow", "1");
316 else if (!strcmp(name
, "I"))
321 else if (!strcmp(name
, "t"))
323 store_parameter("insertstop", "1");
326 else if (!strcmp(name
, "T"))
328 if(!strcasecmp(val
, "mx"))
329 store_parameter("flashversion", "6");
331 store_parameter("flashversion", val
);
335 else if (!strcmp(name
, "f"))
337 store_parameter("storeallcharacters", "1");
338 store_parameter("extrafontdata", "1");
341 else if (!strcmp(name
, "ff"))
344 // append this to the current filter expression (we allow more than one --filter)
345 int l
= strlen(filters
);
346 int new_len
= l
+ strlen(val
) + 2;
347 filters
= (char*)realloc(filters
, new_len
);
349 strcpy(filters
+l
+1, val
);
351 filters
= strdup(val
);
355 else if (!strcmp(name
, "w"))
357 store_parameter("linksopennewwindow", "0");
360 else if (!strcmp(name
, "O"))
364 if(val
&& val
[0] && val
[1]==0 && isdigit(val
[0])) {
369 store_parameter("poly2bitmap", "1");
371 store_parameter("bitmapfonts", "1");
373 store_parameter("ignoredraworder", "1");
376 else if (!strcmp(name
, "G"))
378 //store_parameter("optimize_polygons", "1");
382 else if (!strcmp(name
, "F"))
384 char *s
= strdup(val
);
386 while(l
&& s
[l
-1]=='/') {
390 fontpaths
[fontpathpos
++] = s
;
393 else if (!strcmp(name
, "l"))
396 sprintf(buf
, "%s/default_loader.swf", SWFDIR
);
397 preloader
= strdup(buf
);
400 else if (!strcmp(name
, "b"))
403 sprintf(buf
, "%s/default_viewer.swf", SWFDIR
);
404 viewer
= strdup(buf
);
407 else if (!strcmp(name
, "L"))
415 systemf("ls %s/*_loader.swf", SWFDIR
);
422 else if (!strcmp(name
, "B"))
430 systemf("ls %s/*_viewer.swf", SWFDIR
);
437 else if (!strcmp(name
, "j"))
440 store_parameter("jpegquality", &name
[1]);
443 store_parameter("jpegquality", val
);
447 else if (!strcmp(name
, "V"))
449 printf("pdf2swf - part of %s %s\n", PACKAGE
, VERSION
);
454 fprintf(stderr
, "Unknown option: -%s\n", name
);
460 static struct options_t options
[] = {
469 {"j", "jpegquality"},
473 {"T", "flashversion"},
476 {"b", "defaultviewer"},
477 {"l", "defaultloader"},
491 int args_callback_longoption(char*name
,char*val
) {
492 return args_long2shortoption(options
, name
, val
);
495 int args_callback_command(char*name
, char*val
) {
501 fprintf(stderr
, "Error: Do you want the output to go to %s or to %s?",
510 void args_callback_usage(char *name
)
513 printf("Usage: %s [-options] file.pdf -o file.swf\n", name
);
515 printf("-h , --help Print short help message and exit\n");
516 printf("-V , --version Print version info and exit\n");
517 printf("-o , --output file.swf Direct output to file.swf. If file.swf contains '%%' (file%%.swf), then each page goes to a separate file.\n");
518 printf("-p , --pages range Convert only pages in range with range e.g. 1-20 or 1,4,6,9-11 or\n");
519 printf("-P , --password password Use password for deciphering the pdf.\n");
520 printf("-v , --verbose Be verbose. Use more than one -v for greater effect.\n");
521 printf("-z , --zlib Use Flash 6 (MX) zlib compression.\n");
522 printf("-i , --ignore Allows pdf2swf to change the draw order of the pdf. This may make the generated\n");
523 printf("-j , --jpegquality quality Set quality of embedded jpeg pictures to quality. 0 is worst (small), 100 is best (big). (default:85)\n");
524 printf("-s , --set param=value Set a SWF encoder specific parameter. See pdf2swf -s help for more information.\n");
525 printf("-w , --samewindow When converting pdf hyperlinks, don't make the links open a new window. \n");
526 printf("-t , --stop Insert a stop() command in each page. \n");
527 printf("-T , --flashversion num Set Flash Version in the SWF header to num.\n");
528 printf("-F , --fontdir directory Add directory to the font search path.\n");
529 printf("-b , --defaultviewer Link a standard viewer to the swf file. \n");
530 printf("-l , --defaultloader Link a standard preloader to the swf file which will be displayed while the main swf is loading.\n");
531 printf("-B , --viewer filename Link viewer filename to the swf file. \n");
532 printf("-L , --preloader filename Link preloader filename to the swf file. \n");
533 printf("-q , --quiet Suppress normal messages. Use -qq to suppress warnings, also.\n");
534 printf("-S , --shapes Don't use SWF Fonts, but store everything as shape.\n");
535 printf("-f , --fonts Store full fonts in SWF. (Don't reduce to used characters).\n");
536 printf("-G , --flatten Remove as many clip layers from file as possible. \n");
537 printf("-I , --info Don't do actual conversion, just display a list of all pages in the PDF.\n");
538 printf("-Q , --maxtime n Abort conversion after n seconds. Only available on Unix.\n");
542 float getRate(char*filename
)
546 fi
= open(filename
,O_RDONLY
|O_BINARY
);
549 sprintf(buffer
, "Couldn't open %s", filename
);
553 if(swf_ReadSWF(fi
,&swf
) < 0)
555 fprintf(stderr
, "%s is not a valid SWF file or contains errors.\n",filename
);
560 return swf
.frameRate
/ 256.0;
563 void show_info(gfxsource_t
*driver
, char*filename
)
565 gfxdocument_t
* pdf
= driver
->open(driver
, filename
);
569 msg("<error> Couldn't open %s", filename
);
573 fo
= fopen(outputname
, "wb");
575 perror(outputname
);exit(1);;
581 for(pagenr
= 1; pagenr
<= pdf
->num_pages
; pagenr
++)
583 gfxpage_t
*page
= pdf
->getpage(pdf
,pagenr
);
584 if(is_in_range(pagenr
, pagerange
)) {
585 fprintf(fo
, "page=%d width=%.2f height=%.2f\n", pagenr
, page
->width
, page
->height
);
592 static gfxdevice_t swf
,wrap
,rescale
;
593 gfxdevice_t
*create_output_device()
595 gfxdevice_swf_init(&swf
);
597 /* set up filter chain */
601 gfxdevice_removeclippings_init(&wrap
, &swf
);
605 if(maxwidth
|| maxheight
) {
606 gfxdevice_rescale_init(&rescale
, out
, maxwidth
, maxheight
, 0);
611 gfxfilterchain_t
*chain
= gfxfilterchain_parse(filters
);
613 fprintf(stderr
, "Unable to parse filters: %s\n", filters
);
616 out
= gfxfilterchain_apply(chain
, out
);
617 gfxfilterchain_destroy(chain
);
620 /* pass global parameters to output device */
621 parameter_t
*p
= device_config
;
623 out
->setparameter(out
, p
->name
, p
->value
);
629 int main(int argn
, char *argv
[])
635 char t1searchpath
[1024];
638 int one_file_per_page
= 0;
640 initLog(0,-1,0,0,-1,loglevel
);
642 /* not needed anymore since fonts are embedded
644 fontpaths[fontpathpos++] = concatPaths(installPath, "fonts");
648 srand48(time(0)*getpid());
651 srand(time(0)*getpid());
655 processargs(argn
, argv
);
657 driver
= gfxsource_pdf_create();
659 /* pass global parameters to PDF driver*/
660 parameter_t
*p
= device_config
;
662 driver
->setparameter(driver
, p
->name
, p
->value
);
668 fprintf(stderr
, "Please specify an input file\n");
676 outputname
= stripFilename(filename
, ".swf");
677 msg("<notice> Output filename not given. Writing to %s", outputname
);
683 fprintf(stderr
, "Please use -o to specify an output file\n");
688 // test if the page range is o.k.
689 is_in_range(0x7fffffff, pagerange
);
692 args_callback_usage(argv
[0]);
697 if(password
&& *password
) {
698 sprintf(fullname
, "%s|%s", filename
, password
);
703 driver
->setparameter(driver
, "pages", pagerange
);
706 for(t
=0;t
<fontpathpos
;t
++) {
707 driver
->setparameter(driver
, "fontdir", fontpaths
[t
]);
711 show_info(driver
, filename
);
716 if((u
= strchr(outputname
, '%'))) {
717 if(strchr(u
+1, '%') ||
718 strchr(outputname
, '%')!=u
) {
719 msg("<error> only one %% allowed in filename\n");
722 if(preloader
|| viewer
) {
723 msg("<error> -b/-l/-B/-L not supported together with %% in filename\n");
726 msg("<notice> outputting one file per page");
727 one_file_per_page
= 1;
728 char*pattern
= (char*)malloc(strlen(outputname
)+2);
729 /* convert % to %d */
730 int l
= u
-outputname
+1;
731 memcpy(pattern
, outputname
, l
);
733 strcpy(pattern
+l
+1, outputname
+l
);
734 outputname
= pattern
;
737 gfxdocument_t
* pdf
= driver
->open(driver
, filename
);
739 msg("<error> Couldn't open %s", filename
);
742 /* pass global parameters document */
745 pdf
->setparameter(pdf
, p
->name
, p
->value
);
759 for(pagenr
= 1; pagenr
<= pdf
->num_pages
; pagenr
++)
761 if(is_in_range(pagenr
, pagerange
)) {
763 sprintf(mapping
, "%d:%d", pagenr
, frame
);
764 pdf
->setparameter(pdf
, "pagemap", mapping
);
767 if(pagenum
== xnup
*ynup
|| (pagenr
== pdf
->num_pages
&& pagenum
>1)) {
772 if(pagerange
&& !pagenum
&& frame
==1) {
773 fprintf(stderr
, "No pages in range %s", pagerange
);
779 gfxdevice_t
*out
= create_output_device();;
780 pdf
->prepare(pdf
, out
);
782 for(pagenr
= 1; pagenr
<= pdf
->num_pages
; pagenr
++)
784 if(is_in_range(pagenr
, pagerange
)) {
785 gfxpage_t
* page
= pages
[pagenum
].page
= pdf
->getpage(pdf
, pagenr
);
786 pages
[pagenum
].x
= 0;
787 pages
[pagenum
].y
= 0;
788 pages
[pagenum
].page
= page
;
791 if(pagenum
== xnup
*ynup
|| (pagenr
== pdf
->num_pages
&& pagenum
>1)) {
794 int xmax
[xnup
], ymax
[xnup
];
796 int width
=0, height
=0;
798 memset(xmax
, 0, xnup
*sizeof(int));
799 memset(ymax
, 0, ynup
*sizeof(int));
802 for(x
=0;x
<xnup
;x
++) {
805 if(pages
[t
].page
->width
> xmax
[x
])
806 xmax
[x
] = (int)pages
[t
].page
->width
;
807 if(pages
[t
].page
->height
> ymax
[y
])
808 ymax
[y
] = (int)pages
[t
].page
->height
;
810 for(x
=0;x
<xnup
;x
++) {
814 for(y
=0;y
<ynup
;y
++) {
819 out
->startpage(out
,clip_x2
- clip_x1
, clip_y2
- clip_y1
);
821 out
->startpage(out
,width
,height
);
823 for(t
=0;t
<pagenum
;t
++) {
826 int xpos
= x
>0?xmax
[x
-1]:0;
827 int ypos
= y
>0?ymax
[y
-1]:0;
828 msg("<verbose> Render (%d,%d) move:%d/%d\n",
829 (int)(pages
[t
].page
->width
+ xpos
),
830 (int)(pages
[t
].page
->height
+ ypos
), xpos
, ypos
);
831 pages
[t
].page
->rendersection(pages
[t
].page
, out
, custom_move
? move_x
: xpos
,
832 custom_move
? move_y
: ypos
,
833 custom_clip
? clip_x1
: 0 + xpos
,
834 custom_clip
? clip_y1
: 0 + ypos
,
835 custom_clip
? clip_x2
: pages
[t
].page
->width
+ xpos
,
836 custom_clip
? clip_y2
: pages
[t
].page
->height
+ ypos
);
839 for(t
=0;t
<pagenum
;t
++) {
840 pages
[t
].page
->destroy(pages
[t
].page
);
844 if(one_file_per_page
) {
845 gfxresult_t
*result
= out
->finish(out
);out
=0;
847 sprintf(buf
, outputname
, pagenr
);
848 if(result
->save(result
, buf
) < 0) {
851 result
->destroy(result
);result
=0;
852 out
= create_output_device();;
853 pdf
->prepare(pdf
, out
);
854 msg("<notice> Writing SWF file %s", buf
);
859 if(one_file_per_page
) {
860 // remove empty device
861 gfxresult_t
*result
= out
->finish(out
);out
=0;
862 result
->destroy(result
);result
=0;
864 gfxresult_t
*result
= out
->finish(out
);
865 msg("<notice> Writing SWF file %s", outputname
);
866 if(result
->save(result
, outputname
) < 0) {
869 int width
= (int)(ptroff_t
)result
->get(result
, "width");
870 int height
= (int)(ptroff_t
)result
->get(result
, "height");
871 result
->destroy(result
);result
=0;
873 if(preloader
|| viewer
) {
878 if(!preloader
&& viewer
) {
879 systemf("swfcombine %s -X %d -Y %d \"%s\" viewport=\"%s\" -o \"%s\"",zip
,width
,height
,
880 viewer
, outputname
, outputname
);
884 if(preloader
&& !viewer
) {
885 msg("<warning> --preloader option without --viewer option doesn't make very much sense.");
886 ret
= systemf("swfcombine %s -Y %d -X %d %s/PreLoaderTemplate.swf loader=\"%s\" movie=\"%s\" -o \"%s\"",zip
,width
,height
,
887 SWFDIR
, preloader
, outputname
, outputname
);
891 if(preloader
&& viewer
) {
893 char tmpname
[] = "__swf__XXXXXX";
896 char*tmpname
= "__tmp__.swf";
898 systemf("swfcombine \"%s\" viewport=%s -o %s",
899 viewer
, outputname
, tmpname
);
900 systemf("swfcombine %s -X %d -Y %d -r %f %s/PreLoaderTemplate.swf loader=%s movie=%s -o \"%s\"",zip
,width
,height
,
901 getRate(preloader
), SWFDIR
, preloader
, tmpname
, outputname
);
902 systemf("rm %s", tmpname
);
908 driver
->destroy(driver
);
911 /* free global parameters */
914 parameter_t
*next
= p
->next
;
915 if(p
->name
) free((void*)p
->name
);p
->name
= 0;
916 if(p
->value
) free((void*)p
->value
);p
->value
=0;