1 |
dpavlin |
17 |
#!/usr/bin/perl -w |
2 |
|
|
|
3 |
|
|
# pdf2tiles.pl |
4 |
|
|
# |
5 |
|
|
# 02/24/08 01:22:36 CET Dobrica Pavlinusic <dpavlin@rot13.org> |
6 |
|
|
|
7 |
|
|
use strict; |
8 |
|
|
|
9 |
|
|
use Imager; |
10 |
|
|
use File::Path; |
11 |
|
|
use Data::Dump qw/dump/; |
12 |
|
|
|
13 |
|
|
my $pdf = shift @ARGV || die "usage: $0 filename.pdf"; |
14 |
|
|
|
15 |
dpavlin |
23 |
my $debug = 0; |
16 |
dpavlin |
22 |
|
17 |
dpavlin |
20 |
my $from_page = 1; |
18 |
dpavlin |
23 |
my $to_page = 2; |
19 |
dpavlin |
17 |
|
20 |
dpavlin |
23 |
my $total_pages = $to_page - $from_page + 1; |
21 |
|
|
|
22 |
|
|
my $margin_px = 3; |
23 |
|
|
my $back_color = Imager::Color->new(255, 255, 240); |
24 |
|
|
|
25 |
dpavlin |
18 |
my $tiles_path = 'tiles/basic'; |
26 |
|
|
|
27 |
dpavlin |
20 |
foreach my $path ( $tiles_path, 'ppm' ) { |
28 |
|
|
rmtree $path if -d $path; |
29 |
|
|
mkpath $path || die "can't create $path: $!"; |
30 |
|
|
} |
31 |
|
|
|
32 |
dpavlin |
21 |
print "redering test 100dpi page to get pixel size\n"; |
33 |
|
|
system("pdftoppm -f 1 -l 1 -r 100 $pdf ppm/test") == 0 or die "can't render test: $?"; |
34 |
|
|
my $test = 'ppm/test-000001.ppm'; |
35 |
|
|
open(my $fh, '<', $test) || die "can't open $test: $!"; |
36 |
|
|
my $res = <$fh>; |
37 |
|
|
$res = <$fh>; |
38 |
|
|
my ( $x_res, $y_res ) = split(/\s+/,$res); |
39 |
|
|
print "## 100 dpi resolution = $x_res*$y_res\n"; |
40 |
|
|
close($fh); |
41 |
dpavlin |
17 |
|
42 |
dpavlin |
23 |
$x_res *= $total_pages; |
43 |
|
|
$x_res += $total_pages * $margin_px; |
44 |
dpavlin |
17 |
|
45 |
dpavlin |
21 |
print "## total size = $x_res*$y_res\n"; |
46 |
|
|
|
47 |
dpavlin |
23 |
# initial = 2*1 tiles |
48 |
dpavlin |
22 |
my $curr_w = 256 * 2; |
49 |
dpavlin |
23 |
my $curr_h = 256; |
50 |
dpavlin |
21 |
|
51 |
dpavlin |
24 |
my $x_dpi = int( 100 / ( $x_res / $curr_w ) ) - 1; # 1 dpi margins |
52 |
|
|
my $y_dpi = int( 100 / ( $y_res / $curr_h ) ); |
53 |
dpavlin |
22 |
|
54 |
dpavlin |
24 |
my $start_dpi = $x_dpi < $y_dpi ? $x_dpi : $y_dpi; |
55 |
|
|
|
56 |
dpavlin |
21 |
foreach my $zoom ( 1 .. 10 ) { |
57 |
|
|
|
58 |
|
|
my $dpi = $start_dpi * $zoom; |
59 |
|
|
|
60 |
dpavlin |
20 |
my $ppm = sprintf("ppm/%03d", $dpi); |
61 |
dpavlin |
17 |
|
62 |
dpavlin |
20 |
print "rendering pdf $pdf pages $from_page-$to_page in $dpi dpi\n"; |
63 |
dpavlin |
17 |
|
64 |
dpavlin |
20 |
my $cmd = "pdftoppm -f $from_page -l $to_page -r $dpi -aa yes -aaVector yes $pdf $ppm"; |
65 |
|
|
system($cmd) == 0 or die "can't start $cmd: $?"; |
66 |
dpavlin |
17 |
|
67 |
dpavlin |
20 |
my @page_imgs; |
68 |
dpavlin |
17 |
|
69 |
dpavlin |
20 |
# size of all pages |
70 |
|
|
my ( $x_size, $y_size ) = (0,0); |
71 |
dpavlin |
17 |
|
72 |
dpavlin |
20 |
foreach my $page ( $from_page .. $to_page ) { |
73 |
dpavlin |
17 |
|
74 |
dpavlin |
20 |
my $tmp = sprintf("ppm/%03d-%06d.ppm", $dpi, $page); |
75 |
|
|
die "can't find page $tmp" unless -f $tmp; |
76 |
dpavlin |
17 |
|
77 |
dpavlin |
21 |
my $p_img = Imager->new; |
78 |
|
|
$p_img->read(file=>$tmp) or die "Can't load $tmp: ", $p_img->errstr; |
79 |
dpavlin |
20 |
|
80 |
dpavlin |
23 |
$x_size += $p_img->getwidth() + $margin_px; |
81 |
dpavlin |
21 |
my $h = $p_img->getheight(); |
82 |
dpavlin |
20 |
$y_size = $h if $h > $y_size; |
83 |
|
|
|
84 |
dpavlin |
21 |
push @page_imgs, $p_img; |
85 |
dpavlin |
20 |
} |
86 |
|
|
|
87 |
dpavlin |
23 |
if ( $x_size > $curr_w ) { |
88 |
|
|
print "WARNING: calculated size with margins $x_size > $curr_w\n"; |
89 |
|
|
$x_size = $curr_w; |
90 |
|
|
} |
91 |
|
|
|
92 |
dpavlin |
20 |
print "loaded $from_page-$to_page of $x_size*$y_size pixels\n"; |
93 |
|
|
|
94 |
dpavlin |
22 |
sub pad { |
95 |
|
|
my $s = shift; |
96 |
dpavlin |
23 |
my $l = $s % 256; |
97 |
|
|
return $l ? 256 - $l : 0; |
98 |
dpavlin |
22 |
} |
99 |
|
|
|
100 |
|
|
my ( $full_x, $full_y ) = ( $x_size + pad( $x_size ), $y_size + pad( $y_size ) ); |
101 |
|
|
|
102 |
|
|
my $img = Imager->new( xsize => $full_x, ysize => $full_y ); |
103 |
dpavlin |
20 |
$img->box(filled=>1, color=>$back_color); |
104 |
|
|
|
105 |
dpavlin |
22 |
my $x_pos = int( pad( $x_size ) / 2 ); |
106 |
|
|
my $y_pos = int( pad( $y_size ) / 2 ); |
107 |
dpavlin |
20 |
|
108 |
|
|
foreach my $page_img ( @page_imgs ) { |
109 |
dpavlin |
22 |
$img->paste( left => $x_pos, top => $y_pos, img => $page_img ); |
110 |
dpavlin |
23 |
$x_pos += $page_img->getwidth() + $margin_px; |
111 |
dpavlin |
20 |
} |
112 |
|
|
|
113 |
|
|
undef @page_imgs; |
114 |
|
|
|
115 |
dpavlin |
22 |
$img->write( file => sprintf("zoom-%03d.jpg", $dpi ) ) if $debug; |
116 |
|
|
|
117 |
dpavlin |
17 |
my $tiles_x = int( $x_size / 256 ); |
118 |
|
|
my $tiles_y = int( $y_size / 256 ); |
119 |
|
|
|
120 |
dpavlin |
23 |
my $tx_offset = int( ( $curr_w - $x_size ) / ( 2 * 256 ) ); |
121 |
|
|
my $ty_offset = int( ( $curr_h - $y_size ) / ( 2 * 256 ) ); |
122 |
|
|
|
123 |
dpavlin |
22 |
print "creating in $tiles_x*$tiles_y tiles from $full_x*$full_y\n"; |
124 |
dpavlin |
17 |
|
125 |
|
|
for my $y ( 0 .. $tiles_y ) { |
126 |
|
|
for my $x ( 0 .. $tiles_x ) { |
127 |
|
|
|
128 |
|
|
my $size = { |
129 |
|
|
left => $x * 256, |
130 |
dpavlin |
22 |
bottom => $full_y - $y * 256, |
131 |
|
|
width => 256, |
132 |
|
|
height => 256, |
133 |
dpavlin |
17 |
}; |
134 |
|
|
|
135 |
|
|
my $tile = $img->crop( %$size ) or die "can't crop $x*$y ",dump( $size ); |
136 |
|
|
|
137 |
dpavlin |
23 |
my $tx = $x + $tx_offset; |
138 |
|
|
my $ty = $y + $ty_offset; |
139 |
|
|
|
140 |
dpavlin |
17 |
# emulate TileCache disk layout |
141 |
dpavlin |
18 |
my $path = sprintf("%s/%02d/%03d/%03d/%03d/%03d/%03d/%03d.png", |
142 |
|
|
$tiles_path, |
143 |
dpavlin |
17 |
$zoom - 1, # starts with 0 |
144 |
dpavlin |
23 |
int( $tx / 1000000 ), |
145 |
|
|
int( $tx / 1000 ) % 1000, |
146 |
|
|
$tx % 1000, |
147 |
|
|
int( $ty / 1000000 ), |
148 |
|
|
int( $ty / 1000 ) % 1000, |
149 |
|
|
$ty % 1000 |
150 |
dpavlin |
17 |
); |
151 |
|
|
|
152 |
|
|
my $dir = $path; |
153 |
|
|
$dir =~ s,/[^/]+$,,; |
154 |
|
|
mkpath $dir unless -d $dir; |
155 |
|
|
|
156 |
|
|
$tile->write( file => $path ) or die $tile->errstr; |
157 |
|
|
|
158 |
|
|
undef $tile; |
159 |
|
|
|
160 |
dpavlin |
23 |
printf("# %2dx%-2d => %2dx%-2d %s\n", $x, $y, $tx, $ty, $path); |
161 |
dpavlin |
17 |
|
162 |
|
|
} |
163 |
|
|
} |
164 |
dpavlin |
21 |
|
165 |
|
|
# break if zoom level over 300dpi |
166 |
|
|
last if $dpi > 300; |
167 |
dpavlin |
23 |
|
168 |
|
|
# increase virtual size twice |
169 |
|
|
$curr_w += $curr_w; |
170 |
|
|
$curr_h += $curr_h; |
171 |
dpavlin |
17 |
} |
172 |
|
|
|
173 |
|
|
|