############################################################################### # # PDFパーサ # ############################################################################### package plugin::pdf::PDFParser; use strict; use vars qw(@ISA); use Wiki::Parser; use PDFJ 'EUC'; use Image::Info qw(image_info dim); @ISA = qw(Wiki::Parser); #============================================================================== # コンストラクタ #============================================================================== sub new { my $class = shift; my $self = Wiki::Parser->new(shift); $self->{pagename} = shift; my @Pagesize = (595, 842); # A4 210mm x 297mm my @Margin = (72, 72, 72, 72); # (left, right, top, bottom) 1inch my $Fontsize = 10.5; my $FontsizeHeader = 9; my $FontsizeFooter = 9; my $Font = "Ryumin-Light"; my $FontHeader = "GothicBBB-Medium"; my $FontFooter = "GothicBBB-Medium"; my $Encoding = "EUC-H"; my $HFont = "Times-Roman"; my $HFontHeader = "Helvetica"; my $HFontFooter = "Helvetica"; my $Linewidth = $Pagesize[0] - $Margin[0] - $Margin[1]; my $PageHeight = $Pagesize[1] - $Margin[2] - $Margin[3]; my @PosBody = ($Margin[0], $Pagesize[1] - $Margin[3]); my @PosHeader = ($Margin[0], $Pagesize[1] - $Margin[3] + $Margin[2] / 2); my @PosFooter = ($Margin[0], $Margin[3] / 2); my $Tabwidth = 4; $self->{footer_x} = $PosFooter[0]; $self->{footer_y} = $PosFooter[1]; $self->{height} = $PageHeight; $self->{width} = $Linewidth; my $doc = PDFJ::Doc->new(1.2, @Pagesize); $doc->filter('a'); my $font = $doc->new_font($Font, $Encoding, $HFont); my $font_header = $doc->new_font($FontHeader, $Encoding, $HFontHeader); my $font_footer = $doc->new_font($FontFooter, $Encoding, $HFontHeader); my $font_pre = $doc->new_font($FontFooter, $Encoding); $self->{tstyle} = { normal => TStyle(font => $font, fontsize => $Fontsize), head1 => TStyle(font => $font_footer, fontsize => $Fontsize+5), head2 => TStyle(font => $font_footer, fontsize => $Fontsize+2), head3 => TStyle(font => $font_header, fontsize => $Fontsize+1), verbatim => TStyle(font => $font_pre , fontsize => $Fontsize-2), footer => TStyle(font => $font_footer, fontsize => $FontsizeFooter) }; $self->{pstyle} = { head1 => PStyle(size => $Linewidth, linefeed => '100%', align => 'b', preskip => 10, postskip => 5), head2 => PStyle(size => $Linewidth, linefeed => '100%', align => 'b', preskip => 10, postskip => 5), head3 => PStyle(size => $Linewidth, linefeed => '100%', align => 'b', preskip => 10, postskip => 5), defitem => PStyle(size => $Linewidth, linefeed => '100%', align => 'b', preskip => 1, postskip => 1), normal => PStyle(size => $Linewidth, linefeed => '150%', align => 'w', preskip => 2.5, postskip => 2.5), verbatim => PStyle(size => $Linewidth, linefeed => '100%', align => 'w', preskip => 2.5, postskip => 2.5,beginindent => 20), footer => PStyle(size => $Linewidth, linefeed => '100%', align => 'm'), }; $self->{doc} = $doc; $self->{indent} = 20; $self->{table} = 1; $self->{style} = $self->{tstyle}->{normal}; $self->{last} = ""; return bless $self,$class; } #============================================================================== # ファイルに保存します #============================================================================== sub save_file { my $self = shift; my $file = shift; my $block = Block('V', @{$self->{paras}}, BStyle()); for my $part( $block->break($self->{height}) ) { my $page = $self->{doc}->new_page; $part->show($page, 72, 72 + $self->{height}); my $footer = Paragraph(Text($page->pagenum, $self->{tstyle}->{footer}), $self->{pstyle}->{footer}); $footer->show($page, $self->{footer_x},$self->{footer_y}); } $self->{doc}->print($file); } #============================================================================== # スタイルを上書き #============================================================================== sub update_style { my $self = shift; my $obj = shift; my $style = shift; my $array = []; foreach(@$obj){ push @$array,Text($_->{texts},$style); } return $array; } #============================================================================== # Textのテキストのみを取得 #============================================================================== sub get_texts { my $self = shift; my $obj = shift; my $texts = ""; foreach my $textobj (@$obj){ foreach(@{$textobj->{texts}}){ $texts .= $_; } } return $texts; } sub end_parse { my $self = shift; $self->end_text; $self->end_verbatim; $self->end_numlist; } sub l_headline { my $self = shift; my $level = shift; my $obj = shift; my $texts = $self->get_texts($obj); $self->end_text; $self->end_verbatim; $self->end_numlist; $self->{table} = 1; if($level==1){ my @outline; push @outline,Outline($texts, 0), Dest($texts), $texts; push(@{$self->{paras}},Paragraph(Text([@outline], $self->{tstyle}->{head1}),$self->{pstyle}->{head1})); } elsif($level==2){ my @outline; push @outline,Outline($texts, 1), Dest($texts), $texts; push(@{$self->{paras}},Paragraph(Text([@outline], $self->{tstyle}->{head2}),$self->{pstyle}->{head2})); } elsif($level==3){ my @outline; push @outline,Outline($texts, 2), Dest($texts), "■".$texts; push(@{$self->{paras}},Paragraph(Text([@outline], $self->{tstyle}->{head3}),$self->{pstyle}->{head3})); } $self->{last} = "headline"; } sub l_list { my $self = shift; my $level = shift; my $obj = shift; $self->end_text; $self->end_verbatim; # $self->end_numlist; $self->{table} = 1; my $liststyle = $self->{pstyle}->{defitem}->clone(beginindent => [$level*$self->{indent},$level*$self->{indent}+8], align => 'b'); if($self->{last} ne "list"){ push(@{$self->{paras}},Paragraph(Text(" ",$self->{tstyle}->{normal}),$self->{pstyle}->{normal})); } push(@{$self->{paras}},Paragraph(Text("・",@{$obj},$self->{tstyle}->{normal}),$liststyle)); $self->{last} = "list"; } sub l_numlist { my $self = shift; my $level = shift; my $obj = shift; $self->end_text; $self->end_verbatim; $self->{table} = 1; if($self->{last_numlist} < $level){ $self->{numlist}->{$level}=0; } $self->{numlist}->{$level}++; $self->{last_numlist}=$level; my $liststyle = $self->{pstyle}->{defitem}->clone(beginindent => [$level*$self->{indent},$level*$self->{indent}+8], align => 'b'); if($self->{last} ne "list"){ push(@{$self->{paras}},Paragraph(Text(" ",$self->{tstyle}->{normal}),$self->{pstyle}->{normal})); $self->{numlist}->{$level} = 1; } push(@{$self->{paras}},Paragraph(Text($self->{numlist}->{$level}.".",@{$obj},$self->{tstyle}->{normal}),$liststyle)); $self->{last} = "list"; } sub end_numlist { my $self = shift; $self->{numlist}->{1} = 0; $self->{numlist}->{2} = 0; $self->{numlist}->{3} = 0; } sub l_paragraph { my $self = shift; $self->end_text; $self->end_verbatim; $self->end_numlist; $self->{table} = 1; $self->{last} = "para"; } sub l_verbatim { my $self = shift; my $text = shift; $self->end_text; $self->end_numlist; $self->{table} = 1; # 行末の空白文字は除去する $text =~ s/(?:\s)+$//o; push(@{$self->{pre}},$text); push(@{$self->{pre}},NewLine()); $self->{last} = "pre"; } sub end_verbatim { my $self = shift; if($#{$self->{pre}}>=0){ push(@{$self->{paras}},Paragraph(Text(" ",$self->{tstyle}->{normal}),$self->{pstyle}->{normal})); push(@{$self->{paras}}, Paragraph(Text(@{$self->{pre}},$self->{tstyle}->{verbatim}),$self->{pstyle}->{verbatim})); $self->{pre} = []; } } sub l_text { my $self = shift; my $obj = shift; $self->end_verbatim; $self->end_numlist; $self->{table} = 1; if($self->{last} ne "text" && $self->{last} ne "null" && $self->{last} ne "headline"){ push(@{$self->{paras}},Paragraph(Text(" ",$self->{tstyle}->{normal}),$self->{pstyle}->{normal})); } foreach(@$obj){ push(@{$self->{text}},$_); } if($self->{wiki}->config('br_mode')==1){ push(@{$self->{text}},NewLine()); } $self->{last} = "text"; } sub end_text { my $self = shift; if($#{$self->{text}}>=0){ push(@{$self->{paras}},Paragraph(Text(@{$self->{text}},$self->{tstyle}->{normal}),$self->{pstyle}->{normal})); $self->{text} = []; } } sub l_table { my $self = shift; my $row = shift; $self->end_text; $self->end_verbatim; $self->end_numlist; my $align = "b"; if($self->{table}==1){ $align = "m"; $self->{table} = 0; } my $width = $self->{width} / ($#{$row}+1); my $pstyle = $self->{pstyle}->{normal}->clone(size=>$width,align=>$align); my @blocks; foreach my $cell (@$row){ if($#{@$cell}==-1){ push(@$cell,Text("--",$self->{tstyle}->{normal})); } my $block = Block('V',Paragraph(Text($cell,$self->{tstyle}->{normal}),$pstyle), BStyle(withbox=>'s',padding=>5,align=>'m')); push @blocks,$block; } my $row_block = Block('H',@blocks,BStyle(adjust=>1,width=>$self->{width})); push @{$self->{paras}},$row_block; $self->{last} = "table"; } sub l_explanation { my $self = shift; my $obj1 = shift; my $obj2 = shift; $self->end_text; $self->end_verbatim; $self->end_numlist; $self->{table} = 1; if($self->{last} ne "explanation" && $self->{last} ne "null"){ push(@{$self->{paras}},Paragraph(Text(" ",$self->{tstyle}->{normal}),$self->{pstyle}->{normal})); } push(@{$self->{paras}}, Paragraph(Text(@$obj1,$self->{tstyle}->{normal}),$self->{pstyle}->{normal})); push(@{$self->{paras}}, Paragraph(Text(@$obj2,$self->{tstyle}->{normal}),$self->{pstyle}->{verbatim})); $self->{last} = "explanation"; } sub l_quotation { my $self = shift; my $obj = shift; $self->end_text; $self->end_verbatim; $self->end_numlist; $self->{table} = 1; if($self->{last} ne "quote" && $self->{last} ne "null"){ push(@{$self->{paras}},Paragraph(Text(" ",$self->{tstyle}->{normal}),$self->{pstyle}->{normal})); } push(@{$self->{paras}}, Paragraph(Text(@$obj,$self->{tstyle}->{verbatim}),$self->{pstyle}->{verbatim})); $self->{last} = "quote"; } sub l_line { my $self = shift; $self->end_text; $self->end_verbatim; $self->end_numlist; $self->{table} = 1; push @{$self->{paras}},Paragraph(Text(Shape->line(0,0,$self->{width},0),$self->{tstyle}->{normal}),$self->{pstyle}->{normal}); $self->{last} = "line"; } sub bold { my $self = shift; my $text = shift; return Text($self->parse_line($text),$self->{style}); } sub italic { my $self = shift; my $text = shift; return Text($self->parse_line($text),$self->{style}); } sub underline { my $self = shift; my $text = shift; return Text($self->parse_line($text),$self->{style}); } sub denialline { my $self = shift; my $text = shift; return Text($self->parse_line($text),$self->{style}); } sub url_anchor { my $self = shift; my $url = shift; my $name = shift; if($name eq ""){ $name = $url; } my $style = $self->{style}->clone(withbox=>'b',withboxstyle=>SStyle(link=>"URI:$url")); return Text($name,$style); } sub wiki_anchor { my $self = shift; my $page = shift; my $name = shift; if($name eq ""){ $name = $page; } my $uri = "URI:".$self->{wiki}->get_CGI->url().$self->{wiki}->get_CGI()->path_info(); $uri .= "?page=".Util::url_encode($page); my $style = $self->{style}->clone(withbox=>'b',withboxstyle=>SStyle(link=>$uri)); return Text($name,$style); } sub text { my $self = shift; my $text = shift; return Text($text,$self->{style}); } #=============================================================================== # プラグインの処理。 #=============================================================================== sub plugin { my $self = shift; my $plugin = shift; my $info = $self->{wiki}->get_plugin_info($plugin->{command}); # Wiki形式のプラグインのみ実行 if($info->{FORMAT} eq "WIKI"){ return $self->{wiki}->process_plugin($plugin,$self); } else { return undef; } } sub l_plugin { my $self = shift; my $plugin = shift; my $info = $self->{wiki}->get_plugin_info($plugin->{command}); $self->end_text; $self->end_verbatim; # Wiki形式のプラグインのみ実行 if($info->{FORMAT} eq "WIKI"){ $self->{wiki}->process_plugin($plugin,$self); } return undef; } sub l_image { my $self = shift; my $page = shift; my $file = shift; $self->end_text; $self->end_verbatim; unless($file =~ /\.jpe?g$/i){ return; } my $filename = $self->{wiki}->config('attach_dir')."/".&Util::url_encode($page).".".&Util::url_encode($file); my $info = image_info($filename); my $width = $info->{width}; my $height = $info->{height}; if($width > $self->{width}){ $width = $self->{width}; $height = $height * ($width / $info->{width}) } my $imgobj = $self->{doc}->new_image($filename,$info->{width},$info->{height},$width,$height,0,$info->{'color_type'}); push @{$self->{paras}},$imgobj; } 1;