1 |
#!/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 |
my $from_page = 1; |
16 |
my $to_page = 4; |
17 |
|
18 |
my $tiles_path = 'tiles/basic'; |
19 |
|
20 |
foreach my $path ( $tiles_path, 'ppm' ) { |
21 |
rmtree $path if -d $path; |
22 |
mkpath $path || die "can't create $path: $!"; |
23 |
} |
24 |
|
25 |
print "redering test 100dpi page to get pixel size\n"; |
26 |
system("pdftoppm -f 1 -l 1 -r 100 $pdf ppm/test") == 0 or die "can't render test: $?"; |
27 |
my $test = 'ppm/test-000001.ppm'; |
28 |
open(my $fh, '<', $test) || die "can't open $test: $!"; |
29 |
my $res = <$fh>; |
30 |
$res = <$fh>; |
31 |
my ( $x_res, $y_res ) = split(/\s+/,$res); |
32 |
print "## 100 dpi resolution = $x_res*$y_res\n"; |
33 |
close($fh); |
34 |
|
35 |
$x_res *= ( $to_page - $from_page + 1 ); |
36 |
|
37 |
print "## total size = $x_res*$y_res\n"; |
38 |
|
39 |
# initial width = 2 tiles |
40 |
my $start_dpi = int( 100 / ( $x_res / 512 ) ); |
41 |
|
42 |
foreach my $zoom ( 1 .. 10 ) { |
43 |
|
44 |
my $dpi = $start_dpi * $zoom; |
45 |
|
46 |
my $ppm = sprintf("ppm/%03d", $dpi); |
47 |
|
48 |
print "rendering pdf $pdf pages $from_page-$to_page in $dpi dpi\n"; |
49 |
|
50 |
my $cmd = "pdftoppm -f $from_page -l $to_page -r $dpi -aa yes -aaVector yes $pdf $ppm"; |
51 |
system($cmd) == 0 or die "can't start $cmd: $?"; |
52 |
|
53 |
my @page_imgs; |
54 |
|
55 |
# size of all pages |
56 |
my ( $x_size, $y_size ) = (0,0); |
57 |
|
58 |
foreach my $page ( $from_page .. $to_page ) { |
59 |
|
60 |
my $tmp = sprintf("ppm/%03d-%06d.ppm", $dpi, $page); |
61 |
die "can't find page $tmp" unless -f $tmp; |
62 |
|
63 |
my $p_img = Imager->new; |
64 |
$p_img->read(file=>$tmp) or die "Can't load $tmp: ", $p_img->errstr; |
65 |
|
66 |
$x_size += $p_img->getwidth(); |
67 |
my $h = $p_img->getheight(); |
68 |
$y_size = $h if $h > $y_size; |
69 |
|
70 |
push @page_imgs, $p_img; |
71 |
} |
72 |
|
73 |
print "loaded $from_page-$to_page of $x_size*$y_size pixels\n"; |
74 |
|
75 |
my $back_color = Imager::Color->new(255, 127, 127); |
76 |
|
77 |
my $img = Imager->new( xsize => $x_size, ysize => $y_size ); |
78 |
$img->box(filled=>1, color=>$back_color); |
79 |
|
80 |
my $x_pos = 0; |
81 |
|
82 |
foreach my $page_img ( @page_imgs ) { |
83 |
$img->paste( left => $x_pos, top => 0, img => $page_img ); |
84 |
$x_pos += $page_img->getwidth(); |
85 |
} |
86 |
|
87 |
undef @page_imgs; |
88 |
|
89 |
my $tiles_x = int( $x_size / 256 ); |
90 |
my $tiles_y = int( $y_size / 256 ); |
91 |
|
92 |
print "creating in $tiles_x*$tiles_y tiles\n"; |
93 |
|
94 |
for my $y ( 0 .. $tiles_y ) { |
95 |
for my $x ( 0 .. $tiles_x ) { |
96 |
|
97 |
my $size = { |
98 |
left => $x * 256, |
99 |
bottom => $y_size - $y * 256, |
100 |
width => $x == $tiles_x ? $x_size % 256 : 256, |
101 |
height => $y == $tiles_y ? $y_size % 256 : 256, |
102 |
}; |
103 |
|
104 |
my $tile = $img->crop( %$size ) or die "can't crop $x*$y ",dump( $size ); |
105 |
|
106 |
if ( ( $x == $tiles_x ) || ( $y == $tiles_y ) ) { |
107 |
warn "## expand tile to full size\n"; |
108 |
my $t2 = Imager->new(xsize => 256, ysize => 256); |
109 |
$t2->box(filled=>1, color=>$back_color); |
110 |
$t2->paste( |
111 |
top => 256 - $size->{height}, |
112 |
left => 0, |
113 |
src => $tile, |
114 |
); |
115 |
$tile = $t2; |
116 |
} |
117 |
|
118 |
# emulate TileCache disk layout |
119 |
my $path = sprintf("%s/%02d/%03d/%03d/%03d/%03d/%03d/%03d.png", |
120 |
$tiles_path, |
121 |
$zoom - 1, # starts with 0 |
122 |
int( $x / 1000000 ), |
123 |
int( $x / 1000 ) % 1000, |
124 |
$x % 1000, |
125 |
int( $y / 1000000 ), |
126 |
int( $y / 1000 ) % 1000, |
127 |
$y % 1000 |
128 |
); |
129 |
|
130 |
my $dir = $path; |
131 |
$dir =~ s,/[^/]+$,,; |
132 |
mkpath $dir unless -d $dir; |
133 |
|
134 |
$tile->write( file => $path ) or die $tile->errstr; |
135 |
|
136 |
undef $tile; |
137 |
|
138 |
print "# $x*$y -> $path\n"; |
139 |
|
140 |
} |
141 |
} |
142 |
|
143 |
# break if zoom level over 300dpi |
144 |
last if $dpi > 300; |
145 |
} |
146 |
|
147 |
|