GNU为4on1打印重新排列PDF文档

时间:2016-08-16 14:55:50

标签: pdf printing makefile

我有一份PDF文档cards.pdf,我想用4on1双面打印机设置进行打印。我使用GNU makefile来创建文档,这就是我在寻找解决方案的地方。

将在一个页面上打印四页以节省纸张(而实际上a6是我想要的纸张纸张),并且一些页面将打印在背面。但是,我也希望能够在切纸后翻页以找到正确的背面。我知道我需要按照这个顺序重新排列页面:

1  3  5  7 4 2 8 6 
9 11 13 15 ...

我可以使用pdftk来执行此操作,但存在问题:

  1. 文档cards.pdf的页数未知。
  2. cards.pdf的页数不一定是8的倍数。
  3. 重新排列的文档的大小膨胀。 (在我的例子中,从337kB到1.6MB,有91页)
  4. 我正在寻找一种易于处理的GNU make解决方案来重新排列页面而不会使文档膨胀。

2 个答案:

答案 0 :(得分:0)

以下makefile以一种非常糟糕的方式做我想要的事情。为方便起见,我在文档的开头添加了一个空白页面。

qpdf用于获取cards.pdf的页数。 规则PG_EIGHT用于以正确的打印顺序扩展到8页的块。

# declare following rule with = only, no := 
PG_EIGHT = $$((8*$(1)+2)) $$((8*$(1)+4)) $$((8*$(1)+6)) $$((8*$(1)+8)) $$((8*$(1)+5)) $$((8*$(1)+3)) $$((8*$(1)+9)) $$((8*$(1)+7)) 
#
# use a shell escape to get the number of pages of the pdf file with:
# qpdf --show-npages ./cards.pdf
PG_MAX := $$(( $(shell qpdf --show-npages ./cards.pdf) -1 ))
#
#division discards remainder:
BLOCKS := $(shell seq 0 $$(($(PG_MAX) / 8  - 1))) 
PRINT := $(foreach BLOCK,$(BLOCKS),$(call PG_EIGHT,$(BLOCK)))
#
# get the rest (remainder) of the pages with modulo division:
PG_RM := $(shell echo $(PG_MAX)%8 | bc)
# get last page of last BLOCK:
PG_MAX := $$(( $(PG_MAX) - $(PG_RM) ))
#
# do nothing if remainder is 0.
ifeq ($(PG_RM),1)
PRINT += $$(( $(PG_MAX) + 2))
else ifeq ($(PG_RM),2)
PRINT += $$(( $(PG_MAX) + 2)) 0 0 0 0 $$(( $(PG_MAX) + 3))
else ifeq ($(PG_RM),3)
PRINT += $$(( $(PG_MAX) + 2)) $$(( $(PG_MAX) + 4)) 0 0 0 $$(( $(PG_MAX) + 2))
else ifeq ($(PG_RM),4)
PRINT += $$(( $(PG_MAX) + 2)) $$(( $(PG_MAX) + 4)) 0 0 $$(( $(PG_MAX) + 5)) $$(( $(PG_MAX) + 3)) 
else ifeq ($(PG_RM),5)
PRINT += $$(( $(PG_MAX) + 2)) $$(( $(PG_MAX) + 4)) $$(( $(PG_MAX) + 6)) 0 $$(( $(PG_MAX) + 5)) $$(( $(PG_MAX) + 3)) 
else ifeq ($(PG_RM),6)
PRINT += $$(( $(PG_MAX) + 2)) $$(( $(PG_MAX) + 4)) $$(( $(PG_MAX) + 6)) 0 $$(( $(PG_MAX) + 5)) $$(( $(PG_MAX) + 3)) 0 $$(( $(PG_MAX) + 7))
else ifeq ($(PG_RM),7)
PRINT += $$(( $(PG_MAX) + 2)) $$(( $(PG_MAX) + 4)) $$(( $(PG_MAX) + 6)) $$(( $(PG_MAX) + 8)) $$(( $(PG_MAX) + 5)) $$(( $(PG_MAX) + 3)) 0 $$(( $(PG_MAX) + 7))
# remainder cannot be equal to 8.
endif

# fully evaluate the PRINT string:
PRINT := $(shell echo $(PRINT))

print.pdf: makefile cards.pdf
    echo $(BLOCKS)
    pdftk cards.pdf cat $(PRINT) output print.pdf

这段代码的可怕之处在于处理余数和频繁的shell转义。

我不明白为什么它会使文件大小膨胀。

答案 1 :(得分:0)

这是部分GNU make和部分C解决方案。我检查了400页的文件,没有膨胀。如果这是令人满意的,可以将C程序重写为shell脚本并嵌入到makefile中。

我的理解是问题在于为=IFERROR(INDEX(Sheet1!$K$2:$O$7,MATCH(Sheet2!$A2,Sheet1!$A:$A,0),MATCH(Sheet2!F$1,Sheet1!$F2:$J2,0)),"") 生成正确的页码序列。我写了一个小的(< 70lines)C程序,叫做print_order.c来生成那个序列。并且,我修改了pdftk以使用它。

<强> print_order.c

makefile

已修改#include <stdio.h> #include <stdlib.h> int pg_eight [] = {1, 3, 5, 7, 4, 2, 8, 6}; const char* blank_page = "B1"; void advance_pg_eight() { int j=0; for(j=0; j < 8; j++) pg_eight[j] += 8; } void print_pg_eight (long int npages) { int j=0; static int nprinted = 0; for (j=0; j < 8 && nprinted < npages; j++) { if(pg_eight[j] > npages) printf("%4s ", blank_page); else { printf("%4d ", pg_eight[j]); nprinted++; } } } long int get_npages(const char *first_arg) { char *endptr = "Hello"; long int npages = strtol(first_arg, &endptr, 10); if (*endptr != '\0' || npages <= 0) return 0; return npages; } int main (int argc, char* argv[]) { long int npages = 0; int neights = 0, j=0; if (argc < 2) { fprintf(stderr, "%s: Insufficient number of arguments\n", argv[0]); return 0; } npages = get_npages(argv[1]); if (0 == npages) { fprintf(stderr, "%s: Failed to parse number of pages (%s)\n", argv[0], argv[1]); return 0; } neights = npages/8; if (npages % 8 != 0) neights++; for(j = 0; j < neights; j++) { print_pg_eight(npages); advance_pg_eight(); printf("\n"); } printf("\n"); }

makefile

91页的# # use a shell escape to get the number of pages of the pdf file with: # qpdf --show-npages ./cards.pdf NPAGES := $(shell qpdf --show-npages ./cards.pdf) # PRINT := $(shell ./print_order $(NPAGES)) print.pdf: makefile cards.pdf blank.pdf print_order pdftk B=blank.pdf cards.pdf cat $(PRINT) output print.pdf print_order: print_order.c 示例输出:

print_order

1 3 5 7 4 2 8 6 9 11 13 15 12 10 16 14 17 19 21 23 20 18 24 22 25 27 29 31 28 26 32 30 33 35 37 39 36 34 40 38 41 43 45 47 44 42 48 46 49 51 53 55 52 50 56 54 57 59 61 63 60 58 64 62 65 67 69 71 68 66 72 70 73 75 77 79 76 74 80 78 81 83 85 87 84 82 88 86 89 91 B1 B1 B1 90 是第一页空白的pdf的第一页。

使用此解决方案:

  1. 复制C代码以创建B1
  2. 将包含空白首页的pdf复制为print_order.c
  3. 将应重新订购的pdf复制为blank.pdf
  4. 运行cards.pdf
  5. 希望这有帮助。