pdftool.c

来自「SumatraPDF是一款小型开源的pdf阅读工具。虽然玲珑小巧(只有800多K」· C语言 代码 · 共 1,217 行 · 第 1/2 页

C
1,217
字号
	fz_md5init(&digest);	drawloadpage(pagenum, loadtimes);	if (benchmark)		gettime(&start);	ctm = fz_identity();	ctm = fz_concat(ctm, fz_translate(0, -drawpage->mediabox.y1));	ctm = fz_concat(ctm, fz_scale(drawzoom, -drawzoom));	ctm = fz_concat(ctm, fz_rotate(drawrotate + drawpage->rotate));	bbox = fz_roundrect(fz_transformaabb(ctm, drawpage->mediabox));	w = bbox.x1 - bbox.x0;	h = bbox.y1 - bbox.y0;	bh = h / drawbands;	if (drawpattern)	{		sprintf(name, drawpattern, drawcount++);		fd = open(name, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, 0666);		if (fd < 0)			die(fz_throw("ioerror: could not open file '%s'", name));		sprintf(pnmhdr, "P6\n%d %d\n255\n", w, h);		write(fd, pnmhdr, strlen(pnmhdr));	}	error = fz_newpixmap(&pix, bbox.x0, bbox.y0, w, bh, 4);	if (error)		die(error);	memset(pix->samples, 0xff, pix->h * pix->w * pix->n);	for (b = 0; b < drawbands; b++)	{		if (drawbands > 1)			fprintf(stderr, "drawing band %d / %d\n", b + 1, drawbands);		error = fz_rendertreeover(drawgc, pix, drawpage->tree, ctm);		if (error)			die(error);		if (drawpattern)		{			for (y = 0; y < pix->h; y++)			{				unsigned char *src = pix->samples + y * pix->w * 4;				unsigned char *dst = src;				for (x = 0; x < pix->w; x++)				{					dst[x * 3 + 0] = src[x * 4 + 1];					dst[x * 3 + 1] = src[x * 4 + 2];					dst[x * 3 + 2] = src[x * 4 + 3];				}				write(fd, dst, pix->w * 3);				memset(src, 0xff, pix->w * 4);			}		}		fz_md5update(&digest, pix->samples, pix->h * pix->w * 4);		pix->y += bh;		if (pix->y + pix->h > bbox.y1)			pix->h = bbox.y1 - pix->y;	}	fz_droppixmap(pix);	{	    unsigned char buf[16];	    fz_md5final(&digest, buf);	    for (i = 0; i < 16; i++)		fprintf(stderr, "%02x", buf[i]);	}	if (drawpattern)		close(fd);	drawfreepage();	if (benchmark)	{	    gettime(&end);	    elapsed = end - start;	    if (elapsed < drawtimes->min)	    {		drawtimes->min = elapsed;		drawtimes->minpage = pagenum;	    }	    if (elapsed > drawtimes->max)	    {		drawtimes->max = elapsed;		drawtimes->maxpage = pagenum;	    }	    drawtimes->avg += elapsed;	    drawtimes->pages++;	    fprintf(stderr, " time %.3fs",		    elapsed / 1000000.0);	}	fprintf(stderr, "\n");}voiddrawtxt(int pagenum){	fz_error *error;	pdf_textline *line;	fz_matrix ctm;	drawloadpage(pagenum, NULL);	ctm = fz_concat(			fz_translate(0, -drawpage->mediabox.y1),			fz_scale(drawzoom, -drawzoom));	error = pdf_loadtextfromtree(&line, drawpage->tree, ctm);	if (error)		die(error);	pdf_debugtextline(line);	pdf_droptextline(line);	drawfreepage();}voiddrawxml(int pagenum){	drawloadpage(pagenum, NULL);	fz_debugtree(drawpage->tree);	drawfreepage();}voiddrawpages(char *pagelist){	int page, spage, epage;	char *spec, *dash;	struct benchmark loadtimes, drawtimes;	if (!src)		drawusage();	if (benchmark)	{		memset(&loadtimes, 0x00, sizeof (loadtimes));		loadtimes.min = LONG_MAX;		memset(&drawtimes, 0x00, sizeof (drawtimes));		drawtimes.min = LONG_MAX;	}	spec = strsep(&pagelist, ",");	while (spec)	{		dash = strchr(spec, '-');		if (dash == spec)			spage = epage = 1;		else			spage = epage = atoi(spec);		if (dash)		{			if (strlen(dash) > 1)				epage = atoi(dash + 1);			else				epage = pdf_getpagecount(srcpages);		}		if (spage > epage)			page = spage, spage = epage, epage = page;		if (spage < 1)			spage = 1;		if (epage > pdf_getpagecount(srcpages))			epage = pdf_getpagecount(srcpages);		printf("Drawing pages %d-%d...\n", spage, epage);		for (page = spage; page <= epage; page++)		{			switch (drawmode)			{			case DRAWPNM: drawpnm(page, &loadtimes, &drawtimes); break;			case DRAWTXT: drawtxt(page); break;			case DRAWXML: drawxml(page); break;			}		}		spec = strsep(&pagelist, ",");	}	if (benchmark)	{		if (loadtimes.pages > 0)		{			loadtimes.avg /= loadtimes.pages;			drawtimes.avg /= drawtimes.pages;			printf("benchmark[load]: min: %6.3fs (page % 4d), avg: %6.3fs, max: %6.3fs (page % 4d)\n",				loadtimes.min / 1000000.0, loadtimes.minpage,				loadtimes.avg / 1000000.0,				loadtimes.max / 1000000.0, loadtimes.maxpage);			printf("benchmark[draw]: min: %6.3fs (page % 4d), avg: %6.3fs, max: %6.3fs (page % 4d)\n",				drawtimes.min / 1000000.0, drawtimes.minpage,				drawtimes.avg / 1000000.0,				drawtimes.max / 1000000.0, drawtimes.maxpage);		}	}}voiddrawmain(int argc, char **argv){	fz_error *error;	char *password = "";	int c;	enum { NO_FILE_OPENED, NO_PAGES_DRAWN, DREW_PAGES } state;	while ((c = getopt(argc, argv, "b:d:o:r:txm")) != -1)	{		switch (c)		{		case 'b': drawbands = atoi(optarg); break;		case 'd': password = optarg; break;		case 'o': drawpattern = optarg; break;		case 'r': drawzoom = atof(optarg) / 72.0; break;		case 't': drawmode = DRAWTXT; break;		case 'x': drawmode = DRAWXML; break;		case 'm': benchmark = 1; break;		default:			  drawusage();			  break;		}	}	if (optind == argc)		drawusage();	error = fz_newrenderer(&drawgc, pdf_devicergb, 0, 1024 * 512);	if (error)		die(error);	state = NO_FILE_OPENED;	while (optind < argc)	{		if (strstr(argv[optind], ".pdf"))		{			if (state == NO_PAGES_DRAWN)				drawpages("1-");			opensrc(argv[optind], password, 1);			state = NO_PAGES_DRAWN;		}		else		{			drawpages(argv[optind]);			state = DREW_PAGES;		}		optind++;	}	if (state == NO_PAGES_DRAWN)		drawpages("1-");	closesrc();	fz_droprenderer(drawgc);}/* --------------------------------------------------------------------- *//* * Edit tool. * Copy or impose pages from other pdf files into output pdf. *//* for each source pdf, build a list of objects to transplant. * for each source pdf, do the transplants at the end of object collecting. * build a new page tree structure for output. * change page nodes into xobjects for over and n-up modes. * create new page nodes. * create new page tree. */enum { COPY, OVER, NUP2, NUP4, NUP8 };pdf_xref *editxref = nil;fz_obj *editpagelist = nil;fz_obj *editmodelist = nil;fz_obj *editobjects = nil;int editmode = COPY;voideditusage(void){	fprintf(stderr, "usage: mupdftool edit [-o file.pdf] [mode file.pdf pages ... ]\n");	fprintf(stderr, "  mode is one of: copy over 2up 4up 8up\n");	fprintf(stderr, "  pages is a comma separated list of ranges\n");	fprintf(stderr, "  example:\n");	fprintf(stderr, "    mupdftool edit -o output.pdf copy one.pdf 1-3,5,9 two.pdf 1-\n");	exit(1);}voideditcopy(int pagenum){	fz_error *error;	fz_obj *obj;	fz_obj *ref;	fz_obj *num;	printf("copy %s page %d\n", srcname, pagenum);	ref = srcpages->pref[pagenum - 1];	obj = pdf_getpageobject(srcpages, pagenum - 1);	fz_dictdels(obj, "Parent");	/*	fz_dictdels(obj, "B");	fz_dictdels(obj, "PieceInfo");	fz_dictdels(obj, "Metadata");	fz_dictdels(obj, "Annots");	fz_dictdels(obj, "Tabs");	*/	pdf_updateobject(src, fz_tonum(ref), fz_togen(ref), obj);	error = fz_arraypush(editobjects, ref);	if (error)		die(error);	error = fz_newint(&num, editmode);	if (error)		die(error);	error = fz_arraypush(editmodelist, num);	if (error)		die(error);	fz_dropobj(num);}voideditflushobjects(void){	fz_error *error;	fz_obj *results;	int i;	error = pdf_transplant(editxref, src, &results, editobjects);	if (error)		die(error);	for (i = 0; i < fz_arraylen(results); i++)	{		error = fz_arraypush(editpagelist, fz_arrayget(results, i));		if (error)			die(error);	}	fz_dropobj(results);}voideditflushpagetree(void){	/* TODO: merge pages where editmode != COPY by turning them into XObjects	   and creating a new page object with resource dictionary and content	   stream placing the xobjects on the page. */}voideditflushcatalog(void){	fz_error *error;	int rootnum, rootgen;	int listnum, listgen;	fz_obj *listref;	fz_obj *obj;	int i;	/* Create page tree and add back-links */	error = pdf_allocobject(editxref, &listnum, &listgen);	if (error)		die(error);	error = fz_packobj(&obj, "<</Type/Pages/Count %i/Kids %o>>",			fz_arraylen(editpagelist),			editpagelist);	if (error)		die(error);	pdf_updateobject(editxref, listnum, listgen, obj);	fz_dropobj(obj);	error = fz_newindirect(&listref, listnum, listgen);	if (error)		die(error);	for (i = 0; i < fz_arraylen(editpagelist); i++)	{		int num = fz_tonum(fz_arrayget(editpagelist, i));		int gen = fz_togen(fz_arrayget(editpagelist, i));		error = pdf_loadobject(&obj, editxref, num, gen);		if (error)			die(error);		error = fz_dictputs(obj, "Parent", listref);		if (error)			die(error);		pdf_updateobject(editxref, num, gen, obj);		fz_dropobj(obj);	}	/* Create catalog */	error = pdf_allocobject(editxref, &rootnum, &rootgen);	if (error)		die(error);	error = fz_packobj(&obj, "<</Type/Catalog/Pages %r>>", listnum, listgen);	if (error)		die(error);	pdf_updateobject(editxref, rootnum, rootgen, obj);	fz_dropobj(obj);	/* Create trailer */	error = fz_packobj(&editxref->trailer, "<</Root %r>>", rootnum, rootgen);	if (error)		die(error);}voideditpages(char *pagelist){	int page, spage, epage;	char *spec, *dash;	if (!src)		editusage();	spec = strsep(&pagelist, ",");	while (spec)	{		dash = strchr(spec, '-');		if (dash == spec)			spage = epage = 1;		else			spage = epage = atoi(spec);		if (dash)		{			if (strlen(dash) > 1)				epage = atoi(dash + 1);			else				epage = pdf_getpagecount(srcpages);		}		if (spage > epage)			page = spage, spage = epage, epage = page;		for (page = spage; page <= epage; page++)		{			if (page < 1 || page > pdf_getpagecount(srcpages))				continue;			editcopy(page);		}		spec = strsep(&pagelist, ",");	}}voideditmain(int argc, char **argv){	char *outfile = "out.pdf";	fz_error *error;	int c;	while ((c = getopt(argc, argv, "o:")) != -1)	{		switch (c)		{		case 'o':			outfile = optarg;			break;		default:			editusage();			break;		}	}	if (optind == argc)		editusage();	error = pdf_newxref(&editxref);	if (error)		die(error);	error = pdf_initxref(editxref);	if (error)		die(error);	error = fz_newarray(&editpagelist, 100);	if (error)		die(error);	error = fz_newarray(&editmodelist, 100);	if (error)		die(error);	while (optind < argc)	{		if (strstr(argv[optind], ".pdf"))		{			if (editobjects)				editflushobjects();			opensrc(argv[optind], "", 1);			error = fz_newarray(&editobjects, 100);			if (error)				die(error);		}		else if (!strcmp(argv[optind], "copy"))			editmode = COPY;		else if (!strcmp(argv[optind], "over"))			editmode = OVER;		else if (!strcmp(argv[optind], "2up"))			editmode = NUP2;		else if (!strcmp(argv[optind], "4up"))			editmode = NUP4;		else if (!strcmp(argv[optind], "8up"))			editmode = NUP8;		else			editpages(argv[optind]);		optind++;	}	if (editobjects)		editflushobjects();	closesrc();	editflushpagetree();	editflushcatalog();	error = pdf_savexref(editxref, outfile, nil);	if (error)		die(error);	pdf_closexref(editxref);}/* --------------------------------------------------------------------- *//* * Main! */voidmainusage(void){	fprintf(stderr, "usage: mupdftool <command> [options...]\n");	fprintf(stderr, "  command is one of: show, draw, clean, edit\n");	exit(1);}intmain(int argc, char **argv){	if (argc >= 2)	{		optind = 2;		if (!strcmp(argv[1], "show"))			showmain(argc, argv);		else if (!strcmp(argv[1], "draw"))			drawmain(argc, argv);		else if (!strcmp(argv[1], "clean"))			cleanmain(argc, argv);		else if (!strcmp(argv[1], "edit"))			editmain(argc, argv);		else			mainusage();	}	else		mainusage();	return 0;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?