#!/usr/bin/perl #timeout=10 #----------------------------------------------------------------------# # Copyright (c) 2018, Isaki Wadajima (@wdzm) All rights reserved. # # Preview.pl : ver 1.1_20201025 # #----------------------------------------------------------------------# use strict; use warnings; use utf8; #標準入出力の文字コード:後で指定(OS判別の後) #binmode STDIN, ":utf8"; #binmode STDOUT, ":utf8"; use vars qw(@ARGV); use vars qw($tmpargv0); use vars qw($path $filepath $filename $doctitle $doctitlefortobira $author $sectitle $docinfo $text $endofpara); use vars qw($emph $emphcanuse $kinsokua $kinsokub $kinsokuc $kinsokud $tmpnobreak $cpl $lpp); use vars qw($fontsize_q $fontsize $rubysize $hashirasize $linespacing_h $lineheight $fontfamily $fontfamilysystem); use vars qw($resolution $expansion $expforprint $printpadding $unit $textencode); use vars qw($column $columnspace $h1size $h2size $h3size $h4size $h5size $h6size); use vars qw($pagemargin $pagepadding $pagepaddingtop $pagepaddingleft $secbodymargintop $secbodymarginleft); use vars qw($pagewidth $pageheight $secbodywidth $secbodyheight $columnwidth $columnheight $articlewidth); use vars qw($hashiraposleft $hashirapostop $hashiraposbottom); use vars qw($colormode @colormodearray @headcolorarray $spreadmode $publishmode $donotusepathflag $startpageisleft); use vars qw(@text $numofchars $numofreturn $numoflines $tmplinefrom $info $wrn $wrnalert @idxtitle @idxpage $idxsrc); use vars qw($state $pclass $pclasscode $p $ptmp $c $cc $tmptag $tmptagtext); use vars qw($src $tmptext $tmptext2 $tmptext3 $tmptext4 $tmplatin); use vars qw($i $hcnt $var $tmpcnt $charcnt $linecnt $columncnt $pagecnt $righthashiraclass); use vars qw($process_real_uid $homedir $wsh); use Encode qw(encode decode from_to); use Encode::Guess qw/cp932 euc-jp 7bit-jis utf8/; ################################################################ # 初期設定(カスタマイズ可能) # ################################################################ #各種モード設定 $colormode = 1; #カラーモード(0:透明に / 1:背景色・ボーダーあり) $spreadmode = 1; #見開きモード(0:単頁 / 1:見開き) $publishmode = 1; #パブリッシュモード(0:オフ / 1:オン) #パブリッシュモードでは章や節、項に見出しをつけることできます。 #記法はMarkdownの見出しと同様です(「# 〜〜」「## 〜〜」など)。 #数値設定 $fontsize_q = 11; #文字サイズ[Q](1Q = 0.25mm) $linespacing_h = 11; #行送り[H](1H = 1Q = 0.25mm 上の文字サイズと同値以上を推奨) $cpl = 42; #一行あたりの文字数 $lpp = 17; #一頁あたりの行数 $column = 1; #段組数 $pagewidth = 105; #頁ヨコ寸法[mm] $pageheight = 148; #頁タテ寸法[mm] $pagepadding = 4; #頁パディング[mm](頁周囲の余白、重要) $pagemargin = 4; #頁マージン[mm](並べた時の頁同士の間隔) #フォント設定 $fontfamily = "'YuMincho', 'Yu Mincho', serif"; #本文 $fontfamilysystem = "'HiraKakuProN-W3', 'Meiryo UI', sans-serif"; #ヘッダ・フッタ部 $emph = '﹅'; #圏点に使用する文字 #本文カラーリング(文字色や紙色) if ($colormode) { #通常モード @colormodearray = ('black', 'white', 'lightgray', 'solid 1px black'); } else { #透明モード @colormodearray = ('unset', 'transparent', 'transparent', 'none'); } #ヘッダ・フッタ部のカラーリング @headcolorarray = ('#001133', 'white'); #各種見出しの文字サイズ比率([em]:通常の級数に対する倍率で指定) #※パブリッシュモード時のみ有効 $h1size = 2; #(作品タイトルは本文中に表示されないので事実上未使用) $h2size = 2; #章(大見出し)の文字サイズ[em] $h3size = 1.5; #節(小見出し)の文字サイズ[em] $h4size = 1.2; #項①の文字サイズ[em] $h5size = 1.2; #項②の文字サイズ[em] $h6size = 0.9; #区切り記号等の文字サイズ[em] #publishmodeに連動 (別個に設定もできるけど連動させておくのがオススメの設定たち) $donotusepathflag = $publishmode; #ファイルパス利用の可否(0:パスを明記 / 1:パスを隠す) $startpageisleft = $publishmode; #最初の頁(0:右頁 / 1:左頁) ################################################################ #自動計算 $fontsize = $fontsize_q / 4; #文字サイズ[mm](Qからmmに変換、1Q = 0.25mm) $lineheight = $fontsize + ($linespacing_h / 4); #行送り[mm](推奨:基本文字サイズの2倍以上) $rubysize = $fontsize / 2; #ルビの文字サイズ[mm](推奨:基本文字サイズの半分以下) $hashirasize = $fontsize * 3 / 4; #柱・ノンブルの文字サイズ[mm] #頁パディングは実際にはこちらの変数を使用(自動調節機能のため、上下と左右を分ける) $pagepaddingtop = $pagepadding; #頁上下パディング[mm] $pagepaddingleft = $pagepadding; #頁左右パディング[mm] #柱・ノンブルの位置 $hashiraposleft = $pagepadding; #小口からの距離[mm] $hashirapostop = $pagepadding; #天からの距離[mm] $hashiraposbottom = $pagepadding; #地からの距離[mm] $columnspace = $fontsize * 5; #段組間のアキ[mm] $columnwidth = $lineheight * $lpp; #段組ヨコ寸法[mm] $columnheight = $fontsize * $cpl; #段組タテ寸法[mm] $secbodywidth = $columnwidth; #本文部分ヨコ寸法[mm] $secbodyheight = ($columnheight * $column) + ($columnspace * ($column - 1)); #本文部分タテ寸法[mm] #本文領域上下パディング[mm] $secbodymargintop = ($pageheight - ($pagepaddingtop * 2) - $secbodyheight) / 2; if ($secbodymargintop < 0) { $pagepaddingtop += $secbodymargintop; $secbodymargintop = 0; if ($pagepaddingtop < 0) { $secbodyheight += $pagepaddingtop; $pagepaddingtop = 0; } } #本文領域左右パディング[mm] $secbodymarginleft = ($pagewidth - ($pagepaddingleft * 2) - $secbodywidth) / 2; if ($secbodymarginleft < 0) { $pagepaddingleft += $secbodymarginleft; $secbodymarginleft = 0; if ($pagepaddingleft < 0) { $secbodywidth += $pagepaddingleft; $pagepaddingleft = 0; } } #article幅[mm] if ($spreadmode) { $articlewidth = $pagewidth * 2 + ($pagemargin + 0.1) * 4 + 2; } else { $articlewidth = $pagewidth + ($pagemargin + 0.1) * 2 + 2; } #単位(ここは変えちゃダメ) $unit = 'mm'; #拡大率 [推奨2以上](chrome最小フォントサイズ対策、および拡大縮小機能実装のため) $expansion = 2; #(未使用)画面解像度 $resolution = 96; #(未使用)プリント時の印刷不可能範囲の幅[mm] $printpadding = 15; #(未使用)プリント時の縮小率 $expforprint = getExpforprint($pagewidth, $pageheight, $printpadding); #圏点として使われていそうな文字 $emphcanuse = '・、,.•◦﹅﹆●○▲△◎◉'; #禁則文字A:行頭禁則(ぶら下げ) $kinsokua = "、。,."; #禁則文字B:行頭禁則(ひとつ前の文字とまとめて追い出し) $kinsokub = "}〕〉》」』】〙〗〟’”⦆»"; $kinsokub .= "ゝゞーァィゥェォッャュョヮヵヶぁぃぅぇぉっゃゅょゎゕゖㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇷ゚ㇺㇻㇼㇽㇾㇿ々〻"; $kinsokub .= "?!?!‼⁇⁈⁉・:;:;/"; #禁則文字C:行末禁則(追い出し) $kinsokuc = "{〔〈《「『【〘〖〝‘“⦅«"; #禁則文字D:分離禁止(ひとつ前の文字とまとめて追い出し) $kinsokud = "—―─…‥〳〴〵"; #段落の最後に強制的に入れるコード $endofpara = ' 
'; ################################################################ ######## メインルーチン ######## &run(); sub run { #引数を格納 $filepath = $ARGV[0]; $text = $ARGV[1]; #warning格納庫を初期化 $wrn = ""; if ($pagewidth < $secbodywidth + $pagepaddingleft * 2) { $wrn .= "[Warning!] ページ幅(ヨコ寸法)が足りません。\n"; } if ($pageheight < $secbodyheight + $pagepaddingtop * 2 + $hashirapostop + $hashiraposbottom + $hashirasize * 2) { $wrn .= "[Warning!] ページ高さ(タテ寸法)が足りません。\n"; } #第一引数がない場合は終了 if (!$filepath) { print "[Error!] ファイルを指定してください\n"; exit(0); } if ($filepath =~ /^[A-Z]:/) { #英大文字とコロンから始まるパス=windowsのパス #標準入出力の文字コード:Shift-JIS binmode STDIN, ":encoding(cp932)"; binmode STDOUT, ":encoding(cp932)"; #プレビュー用HTMLのパスを生成(マイドキュメント直下、ファイル名固定) $path = $ENV{USERPROFILE}; $path .= "\\My Documents\\miPreview.html"; } else { #その他の場合はMac(UNIX) #標準入出力の文字コード:UTF-8 binmode STDIN, ":utf8"; binmode STDOUT, ":utf8"; #プレビュー用HTMLのパスを生成(ホームディレクトリ直下、ファイル名固定) use Cwd 'realpath'; $process_real_uid = $<; $homedir = (getpwuid($process_real_uid))[7]; $path = Cwd::realpath($homedir); $path .='/miPreview.html'; } if (!$text) { #第二引数(テキスト本文)が存在しない場合 #→パスを頼りに直接ファイルを読んでくる #念のため文字コード判別 #(範囲選択の場合は常にutf8でOK! なのでここで) $textencode = &guessTestcode($filepath); $text = ""; open (IN, $filepath) or die "$!"; while () { $text .= $_; } close (IN); } #何も選択されていない場合→上で強制的に読むようにしました if ($text eq "") { print "[Error!] テキストが空です\n"; exit(0); } #文字コードのデコード:本文 if ($textencode !~ /utf/) { $text = decode($textencode, $text); } else { utf8::decode($text); } #文字コードのデコード:ファイルパス if ($filepath =~ /^[A-Z]:/) { $filepath = decode('Shift-JIS', $filepath); } else { utf8::decode($filepath); } #改行コード処理 #$text =~ s/\x0D\x0A|\x0D|\x0A/\n/g; $text =~ s/\r\n|\r|\n/\n/g; #元ファイルのパスからファイル名のみ抜き出し $filename = $filepath; $filename =~ s!^.+[/\\](.+)$!$1!m; #表題を仮置き(ファイル名から拡張子を取い除いたもの) $doctitle = $filename; $doctitle =~ s/^(.+)[\.?].*$/$1/; #ついでに作者名も(作者名は[]でくくった部分) $author = ""; if ($doctitle =~ /^\[(.+?)\] *(.+)$/) { $doctitle = $2; $author = $1; } elsif ($doctitle =~ /^(.+) *\[(.+?)\]$/) { $doctitle = $1; $author = $2; } #文書の情報(フッタに表示するやつ)を仮置き $docinfo = "(${cpl}文字 × ${lpp}行 × ${column}段)"; #章題を仮置き(空白文字) $sectitle = ""; #----------ルビの処理----------# #置き換え:カクヨム記法圏点をルビの傍点(でんでんマークダウン記法)に $text =~ s!《《(.+?)》》!'{'.$1.'|'.$emph x length($1).'}'!meg; #いま置き換えた奴らを1文字づつ分解 $text =~ s!{(.+?)\|[$emphcanuse]+?}!setParsedemph($1)!meg; #置き換え:パイプ付きルビをでんでんマークダウン記法に $text =~ s/[||]([^\n|{}]+?)《(.+?)》/{$1|$2}/mg; #置き換え:パイプなし(漢字のみ)のルビをでんでんマークダウン記法に $text =~ s/(\p{Han}+)《(.+?)》/{$1|$2}/mg; #----------テキストデータ解析----------# #見出しの状態をチェック $hcnt++ while $text =~ /^#[^#].*$/mg; if ($hcnt and $publishmode and $hcnt > 1) { $wrn .= "[Warning!] 作品タイトル(# から始まる行)が複数あります。\n" } #通常、右頁の柱には章題(h2)を入れるのだけれど…… $righthashiraclass = "h2"; if (!($text =~ /^##[^#].*$/mg)) { #そもそも章(h2)が存在せず、 if ($text =~ /^###[^#].*$/mg) { #でも節(h3)ならあるよって場合は、それを右頁柱に $righthashiraclass = "h3"; } #(項(h4)以降はさすがにいいか……?) } #本文開始前のH1は表題(作品タイトル)として扱う if ($text =~ /^[  \t]*\n*#[  \t]*([^#].*?)\n/s) { $doctitle = $1; #ついでに作者名も(作者名は[]でくくった部分) if ($doctitle =~ /^\[(.+?)\] *(.+?)$/) { $doctitle = $2; $author = $1; } elsif ($doctitle =~ /^(.+?) *\[(.+?)\]$/) { $doctitle = $1; $author = $2; } } #ループに入る前の下準備、各変数を初期化 @text = split(/\n/, $text); @idxtitle = (); @idxpage = (); $numofchars = 0; #文字数 $numofreturn = @text; #改行数(段落数) $numoflines = 0; #行数 $tmptext4 = ''; $tmptext3 = ''; $tmptext2 = ''; $tmptext = ''; $tmplatin = ''; $linecnt = 0; $columncnt = 0; $pagecnt = 0; ($doctitlefortobira = $doctitle) =~ s/[  \t]+/
/g; if ($publishmode and $startpageisleft) { #パブリッシュモードかつ左頁スタート if ($text =~ /^(?:[  \t]*\n|#[^#][^\n]*\n|\n)*##[^#].*\n/s) { #ちゃんと本文開始前にh2(トビラ頁)がある #表紙なくて困るのでページゼロでごまかそう $tmptext4 = "

$doctitlefortobira
$author

"; } else { #h2(トビラ頁)がない #最初の1ページにタイトルを乗っけて逃げる $tmptext4 = < 
 

$doctitlefortobira
$author

1

EOM $pagecnt++; } } $state = ""; #一行ごとの処理 foreach $p (@text) { #パブリッシュモードかつ空行かつ[H2(=トビラ頁)直後または本文開始前]の場合の処理 if ($publishmode and $p eq "" and (($pclass and $pclass eq "h2") or $numofchars == 0)) { next; #空行は無視 } #ここで$pclassをリセット $pclass = ""; $pclasscode = ""; #以下はパブリッシュモード時限定の処理 if ($publishmode) { #見出し行の場合の処理 if ($p =~ /^(#{1,6})[  \t]*(.+)$/) { #とりあえず見出し用メタ文字を削除 $p = $2; $ptmp = ""; if (length($1) == 1) { #H1:表題(作品タイトル) →本文には乗らない $pclass = "h1"; next; #H1は消滅させる } elsif (length($1) == 2) { #H2:章(大見出し) →常にトビラとして1ページ使う(左頁) $pclass = "h2"; } elsif (length($1) == 3) { #H3:節(小見出し) →#改頁(※常に右頁スタートにもできるけど停止中) $pclass = "h3"; $ptmp = " -"; } elsif (length($1) == 4) { #H4:項① →改段組 $pclass = "h4"; $ptmp = " - -"; } elsif (length($1) == 5) { #H5:項② →改ページ等の処理はなし $pclass = "h5"; $ptmp = " - - -"; } elsif (length($1) == 6) { #H6:? →改ページ等の処理はなし $pclass = "h6"; $ptmp = " - - - -"; } push (@idxtitle, "$ptmp $p"); push (@idxpage, ($pagecnt == 0 ? 1 : $pagecnt + 2)); } #見出し行if終了 $pclasscode = ( $pclass eq "" ? "" : " class=\"$pclass\"" ); if ($linecnt > 1) { #頁の開始でないタイミング、かつ、 if ($pclass eq "h2" or $pclass eq "h3") { #章(h2)・節(h3)の切り替わり → 改頁処理 $columncnt++; $pagecnt++; $tmptext3 .= &setColumn($columncnt, $tmptext2); $tmptext4 .= &setSection($pagecnt, $tmptext3); } if ($pclass eq "h4") { #項①(h4)の切り替わり → 改段組処理のみ if ($columncnt + 1 < $column) { #改段組処理 $columncnt++; $tmptext3 .= &setColumn($columncnt, $tmptext2); } else { #改頁処理 $columncnt++; $pagecnt++; $tmptext3 .= &setColumn($columncnt, $tmptext2); $tmptext4 .= &setSection($pagecnt, $tmptext3); } } } if ($pclass eq "h2") { #H2 if ($spreadmode and !(($pagecnt + $startpageisleft) % 2)) { #見開きモードかつ右頁の場合は空白ページ入れる $columncnt++; $pagecnt++; $tmptext4 .= &setSection($pagecnt, ' ', 'blank'); } #右頁柱に使うので出て来るたびに変数にぶっこむ if ($righthashiraclass eq "h2") { $sectitle = $2; } } elsif ($pclass eq "h3") { #H3 if ($spreadmode and ($pagecnt + $startpageisleft) % 2) { #見開きモードかつ左頁の場合は空白ページ入れ……ない #(たぶん必要ないので停止中、必要ならコメントアウト解除) # $columncnt++; # $pagecnt++; # $tmptext4 .= &setSection($pagecnt, ' ', 'blank'); } #(設定によっては)右頁柱に使うので出て来るたびに変数にぶっこむ if ($righthashiraclass eq "h3") { $sectitle = $2; } } } #パブリッシュモード限定if終了 $tmpcnt = 0; #行頭から何文字目かをカウント $charcnt = 0; #段落の文字数をカウント $tmptext = ''; $linecnt++; if ($linecnt > $lpp) { #行数オーバー! → 改段組または改頁処理 if ($columncnt + 1 < $column) { #改段組処理 $columncnt++; $tmptext3 .= &setColumn($columncnt, $tmptext2); $linecnt++; #重要! } else { #改頁処理 #$tmptextは空っぽ!なのでsectionを閉じるだけ! $columncnt++; $pagecnt++; $tmptext3 .= &setColumn($columncnt, $tmptext2); $tmptext4 .= &setSection($pagecnt, $tmptext3); $linecnt++; #重要! } } $tmplinefrom = $linecnt; $state = "honmon"; #一文字ごとの処理 foreach $c (split //, $p) { $cc = ""; if ($state eq "honmon") { if ($c eq "{") { $state = "ruby"; $tmptext .= ""; next; } else { if (&checkChar($c)) { next; } } } elsif ($state eq "ruby") { if ($c eq "|") { $state = "rt"; $tmptext .= ""; next; } else { if (&checkChar($c)) { next; } } } elsif ($state eq "rt") { if ($c eq "}") { $state = "honmon"; $tmptext .= ""; next; } else { $c =~ s//>/; $cc = $c; } } #行末かどうか、および頁末かどうかのチェック(指定文字数での強制改行) if ($tmpcnt == &getTruecpl($cpl, $pclass)) { #行末、だけど改行処理等はしない、行末禁則の処理のみ #禁則処理③(起こしかっこの追い出し) if ($cc =~ /[$kinsokuc]$/) { if ($linecnt < $lpp) { #最終行でなければ→手前に改行を抱き合わせで格納 $tmptext .= "
\n$cc"; $tmpcnt = length("$cc"); #行頭からの位置を初期化 $linecnt++; #行数カウントを+1 } else { #最終行なら→ここで段落を閉じる $tmptext2 .= &setParagraph($tmptext); if ($columncnt + 1 < $column) { #改段組 $columncnt++; $tmptext3 .= &setColumn($columncnt, $tmptext2); } else { #改頁 $columncnt++; $pagecnt++; $tmptext3 .= &setColumn($columncnt, $tmptext2); $tmptext4 .= &setSection($pagecnt, $tmptext3); } $tmplinefrom = 1; $tmptext .= $cc; $tmpcnt = length("$cc"); #行頭からの位置を初期化 $linecnt++; #行数カウントを+1 } next; } } if ($tmpcnt > &getTruecpl($cpl, $pclass)) { #文字数オーバー!(ぶら下げの位置、本来なら次行の先頭) #禁則処理①(句読点のぶら下げ) if ($cc =~ /[$kinsokua]$/) { $tmptext .= $cc; next; } #禁則処理②(受けかっこおよび拗促音の追い出し) if ($cc =~ /[$kinsokub]$/) { if ($linecnt < $lpp) { #最終行でなければ→ひとつ前の文字の前に改行を入れる if ($tmptext =~ /<\/(.+)>[$kinsokua$kinsokub]*$/) { #ルビや英単語、分割禁止文字の対策(タグになってるので) $tmptag = $1; $tmptext =~ s/(?:
|)(<$tmptag.*?>.+<\/$tmptag>[$kinsokua$kinsokub]*)$/
\n$1$cc/; $tmptagtext = $1; $tmptagtext =~ s/(?:<$tmptag.*?>|<\/$tmptag>|.+?<\/rt>)//; } else { $tmptext =~ s/([^$kinsokub][$kinsokua$kinsokub]*)$/
\n$1$cc/; $tmptagtext = $1; } $tmpcnt = length("$tmptagtext$cc"); #行頭からの位置を初期化 $linecnt++; #行数カウントを+1 } else { #最終行なら→ひとつ前の文字の前で段落を閉じる if ($tmptext =~ /<\/(.+)>[$kinsokua$kinsokub]*$/) { #ルビや英単語、分割禁止文字の対策(タグになってるので) $tmptag = $1; $tmptext =~ s/^(.*)(?:
|)(<$tmptag.*>.+<\/$tmptag>[$kinsokua$kinsokub]*)$/$1/; if (defined $2) { $cc = "$2$cc"; } } else { $tmptext =~ s/^(.*)([^$kinsokub][$kinsokua$kinsokub]*)$/$1/; if (defined $2) { $cc = "$2$cc"; } } $tmptext2 .= &setParagraph($tmptext); if ($columncnt + 1 < $column) { #改段組 $columncnt++; $tmptext3 .= &setColumn($columncnt, $tmptext2); } else { #改頁 $columncnt++; $pagecnt++; $tmptext3 .= &setColumn($columncnt, $tmptext2); $tmptext4 .= &setSection($pagecnt, $tmptext3); } $tmplinefrom = 1; $tmptext .= $cc; $tmpcnt = length("$cc"); #行頭からの位置を初期化 $linecnt++; #行数カウントを+1 } next; } ### 禁則ここまで! 以降は普通の改行処理! if ($linecnt >= $lpp) { #頁末(最終行かつ一番下の文字)→改段組または改ページ処理 $tmptext2 .= &setParagraph($tmptext); if ($columncnt + 1 < $column) { #改段組 $columncnt++; $tmptext3 .= &setColumn($columncnt, $tmptext2); } else { #改頁 $columncnt++; $pagecnt++; $tmptext3 .= &setColumn($columncnt, $tmptext2); $tmptext4 .= &setSection($pagecnt, $tmptext3); } $tmplinefrom = 1; #行末処理終了、数値初期化及び更新 $tmpcnt = 1; #行頭からの位置を1文字目に初期化 $linecnt++; #行数カウントを+1 } else { #頁末以外は普通の改行、ただしの中の場合はお預けな! if ($state eq "honmon") { $tmptext .= "
\n"; #行末処理終了、数値初期化及び更新 $tmpcnt = 1; #行頭からの位置を1文字目に初期化 $linecnt++; #行数カウントを+1 } else { #の中で、かつ、 if ($tmpcnt > &getTruecpl($cpl, $pclass)) { #もう限界突破しちゃってるケース →オーケイ、きみは追い出し処理だ(過去に遡って置き換える) $tmptext =~ s/^(.*)(.*?)$/$1
\n$2/s; $tmpcnt = $tmpcnt - &getTruecpl($cpl, $pclass); #行頭からの位置をはみ出した分に(1のはず) $linecnt++; #行数カウントを+1 } } } } $tmptext .= $cc; } #/foreach Level2 $numofchars += $charcnt; $numoflines += $linecnt; $tmptext2 .= &setParagraph($tmptext); #章題の場合はそれだけで1ページ使う(トビラ頁) if ($publishmode and $pclass eq "h2") { $columncnt++; $pagecnt++; $tmptext3 .= &setColumn($columncnt, $tmptext2, $pclass); $tmptext4 .= &setSection($pagecnt, $tmptext3, $pclass); } } #/foreach Level1 #最後のトドメ(最後一文が変数内に残ったままなので書き出す!) if (length($tmptext2) > 0) { $columncnt++; $pagecnt++; $tmptext3 .= &setColumn($columncnt, $tmptext2); $tmptext4 .= &setSection($pagecnt, $tmptext3); $linecnt = 1; $tmplinefrom = 1; } #文書の情報(フッタに表示するやつ) if ($column > 1) { $docinfo = "${numofchars}文字/全${pagecnt}頁(${cpl}文字 × ${lpp}行 × ${column}段)"; } else { $docinfo = "${numofchars}文字/全${pagecnt}頁(${cpl}文字 × ${lpp}行)"; } $wrn =~ s/\n$//s; #標準出力にメッセージ表示 $info = <\n"; for ($i = 0; $i < @idxtitle; $i++) { $idxsrc .= "\n"; } $idxsrc .= "\n"; } $src = $tmptext4; #HTMLファイル書き出し open (OUT, '> '.$path); print OUT &setHtmlcode($src, $filename, $filepath); close (OUT); #ブラウザで開く if ($filepath =~ /^[A-Z]:/) { #win system('start chrome "'.$path.'"'); } else { #Mac system("open $path"); #QuickLookも試してみたけど上手く動かず #system("qlmanage -p $path"); } } #メインおしまい、以下サブルーチンたち #************************************************ # 関数名:sr # 内容:寸法を拡大(chrome最小フォントサイズ対策) # 引数:寸法[mm] # 戻り値:寸法[mm] #************************************************ sub sr { return $_[0] * $expansion; } #************************************************ # <<<未使用>>> # 関数名:pr # 内容:寸法を縮小(プリントアウト時に収まりきらないので縮める) # 引数:寸法[mm] # 戻り値:寸法[mm] #************************************************ sub pr { return $_[0] * $expforprint; } #************************************************ # 関数名:guessTestcode # 内容:文字コード判別 # 引数:判別したいファイルのパス # 戻り値:文字コード名(文字列) #************************************************ sub guessTestcode { my ( $myret, $fh, $temp, $i, $genc ); # unless (open ($fh, '<:raw', $_[0])){ #文字コード指定なしで1回ファイルを開く # die "OPEN FAILED: $file, $! #"; # } open ($fh, $filepath) or die "$!"; while ($temp .= <$fh> and ++$i < 50){ #最大50行(実は49行)まで変数に保存 eof and last; } close ($fh); $genc = guess_encoding($temp); $myret = $genc->name; return $myret; } #************************************************ # 関数名:setParsedemph # 内容:傍点を1文字づつ分解 # 引数:文字列 # 戻り値:整形後の文字列 #************************************************ sub setParsedemph { my ( $myret, $ch ); $myret = ""; foreach $ch (split //, $_[0]) { $myret .= "{$ch|$emph}"; } return $myret; } #************************************************ # 関数名:setSection # 内容:sectionタグ書き込み # 引数:頁数 タグの中身, [オプション] ($pagecnt, $tmptext3, [str]) # 戻り値:整形済み文字列 #************************************************ sub setSection { my ( $myret, $myopt, $mypnext, $mypprev, $mysecclass ); $mypnext = $_[0] + 1; $mypprev = $_[0] - 1; if ($spreadmode) { if ($startpageisleft) { $mypnext += (1 - $_[0] % 2); $mypprev -= $_[0] % 2; } else { $mypnext += $_[0] % 2; $mypprev -= (1 - $_[0] % 2); } } $myopt = ( $_[2] ? $_[2] : "" ); if ($myopt eq "h2") { $mysecclass = "tobirapage"; } elsif ($myopt eq "blank") { $mysecclass = "blankpage"; } else { $mysecclass = ""; } $myret = "
\n"; $myret .= "
".&setHashiratext($_[0])."
\n"; $myret .= "
\n$_[1]
\n"; $myret .= "
$_[0]
\n"; $myret .= "
\n".&setHrforspread($_[0]); $tmptext = ""; $tmptext2 = ""; $tmptext3 = ""; $tmpcnt = 0; $charcnt = 0; $linecnt = 0; $columncnt = 0; $tmplinefrom = 1; return $myret; } #************************************************ # 関数名:setColumn # 内容:columnタグ書き込み # 引数:段組数, タグの中身, [オプション] ($columncnt, $tmptext2, [str]) # 戻り値:整形済み文字列 #************************************************ sub setColumn { my ( $myret, $myopt ); $myopt = ( $_[2] ? $_[2] : "" ); if ($myopt eq "h2") { $myret = "
\n$_[1]
\n"; } else { $myret = "
\n$_[1]
\n"; } $tmptext = ""; $tmptext2 = ""; $tmpcnt = 0; $charcnt = 0; $linecnt = 0; $tmplinefrom = 1; return $myret; } #************************************************ # 関数名:setParagraph # 内容:段落(

)の内容をタグ書き込み # 引数:タグの内容($tmptext) # 戻り値:pタグ(タグ用整形済み文字列) #************************************************ sub setParagraph { my ( $myret ); &checkCharsub(); $myret = "$_[0]$endofpara

\n"; return $myret; } #************************************************ # 関数名:setClassforspread # 内容:見開き用、頁の偶数奇数によりクラスを振り分ける # 引数:頁数、他に指定されるクラス ($pagecnt, $mysecclass) # 戻り値:クラス名(タグ用整形済み文字列) #************************************************ sub setClassforspread { my ( $myif, $myvar ); $myif = ( $startpageisleft ? $_[0] % 2 : !($_[0] % 2)); $myvar = ""; if ($spreadmode) { $myvar = ( $_[0] % 2 ? "leftpage" : "rightpage" ); } $myvar .= ( $myvar and $_[1] ? " $_[1]" : "" ); return ( $myvar ? " class=\"$myvar\"" : "" ); } #************************************************ # 関数名:setHashiratext # 内容:柱のテキストをページの左右で振り分け # 引数:頁数 ($pagecnt) # 戻り値:テキスト #************************************************ sub setHashiratext { # my ( $myif ); # $myif = ( $startpageisleft ? $_[0] % 2 : !($_[0] % 2)); if ($spreadmode) { if ($_[0] % 2) { return $doctitle . ' '; } else { return ' ' . $sectitle; } } else { return ""; } } #************************************************ # 関数名:setHrforspread # 内容:見開き用、左頁の後に水平線入れる # 引数:頁数 ($pagecnt) # 戻り値:HTMLタグ #************************************************ sub setHrforspread { my ( $myif ); $myif = ( $startpageisleft ? $_[0] % 2 : !($_[0] % 2)); if ($spreadmode and $_[0] and $myif) { return "
\n"; } else { return ""; } } #************************************************ # 関数名:setTmplinefrom # 内容:行数の説明文を生成する # 引数:開始行、終了行 ($tmplinefrom, $linecnt) # 戻り値:整形済み文字列 #************************************************ sub setTmplinefrom { my ( $myret ); if ($_[0] != $_[1]) { #複数行の場合、「○行目から○行目(計○行)」 $myret = $_[0]."〜".$_[1]."行目(計".($_[1]-($_[0]-1))."行)"; } else { #一行しかないならそのまま「○行目」 $myret = $_[1]."行目"; } return $myret; } #************************************************ # 関数名:getTruecpl # 内容:一行に最大何文字入るか取得する # 引数:最大文字数、見出しクラス ($cpl, $pclass) # 戻り値:文字数(数値) #************************************************ sub getTruecpl { my ( $myret ); #パブリッシュモードでないならそのまま if (!$publishmode) { return $_[0]; } if (!$_[1]) { #特に見出し行とかでない、普通の本文ならそのまま return $_[0]; } else { #見出し行の場合、文字サイズ比のぶんだけ減る $myret = eval('int($_[0] / $'.$_[1].'size);'); if ($column > 1 and $_[1] eq "h2") { #ただしH2の場合、段組無視の計算を追加 $myret = ($myret * $column) + ($columnspace * ($column - 1) / ($fontsize * $h2size)); } return $myret; } } #************************************************ # 関数名:checkChar # 内容:$cの全角半角をチェック # 引数:文字 ($c) # 戻り値:文字 #************************************************ sub checkChar { my ( $myc ); $myc = $_[0]; #半角英数字の場合 if ($myc =~ /(\p{InBasicLatin})$/) { $tmpcnt += 0.5; if ($1 =~ /[a-zA-z0-9,.;:]/) { $tmplatin .= $myc; if (length($tmplatin) < $cpl * 2) { return 1; } else { $myc = ""; } } } else { $tmpcnt++; } $charcnt++; #禁則処理④(分離禁止文字) #面倒なので貴様は英単語とほぼ同じ扱いにしてくれる if ($myc =~ /[$kinsokud]$/) { $tmpnobreak .= $myc; if (length($tmpnobreak) < $cpl) { return 1; } else { $myc = ""; } } &checkCharsub(); #半角の大なり小なり記号をエスケープ $myc =~ s//>/g; $cc = $myc; return 0; } #************************************************ # 関数名:checkCharsub # 内容:一時格納庫(英単語または分離禁止文字)になんか入ってる場合吐き出させる # 引数:なし # 戻り値:なし #************************************************ sub checkCharsub { my ( $myvar ); $myvar = ""; #英単語格納庫になんか入ってるなら吐き出せ if ($tmplatin ne "") { if ($tmpcnt > &getTruecpl($cpl, $pclass)) { #もう限界突破しちゃってるケース →追い出し処理 $tmptext .= "
"; $tmpcnt = 1 + length($tmplatin) / 2; $linecnt++; } #stateがルビだったりすると動作が前後しちゃうのでちょっとややこしい記法 $myvar = "$tmplatin"; $tmptext =~ s/(<.+>|)$/$myvar$1/; } $tmplatin = ""; $myvar = ""; #分離禁止文字格納庫になんか入ってるなら吐き出せ if ($tmpnobreak and $tmpnobreak ne "") { #ダッシュをちゃんと繋がる奴に置換 $tmpnobreak =~ s/[—―─]/\x{2500}/g; if ($tmpcnt > &getTruecpl($cpl, $pclass)) { #もう限界突破しちゃってるケース →追い出し処理 $tmptext .= "
"; $tmpcnt = 1 + length($tmpnobreak); $linecnt++; } #stateがルビだったりすると動作が前後しちゃうのでちょっとややこしい記法 $myvar = "$tmpnobreak"; $tmptext =~ s/(<.+>|)$/$myvar$1/; } $tmpnobreak = ""; $myvar = ""; return; } #************************************************ # 関数名:getExpforprint # 内容:印刷可能領域に対する縮小率を求める # 引数:頁ヨコ寸法、頁タテ寸法、印刷用余白幅 ($pagewidth, $pageheight, $printpadding) # 戻り値:縮小率(数値) #************************************************ sub getExpforprint { my ( $myret, $myvar ); $myvar = ( $_[0] < $_[1] ? $_[0] : $_[1] ); $myret = ($myvar - ($_[2] * 2)) / $myvar; return $myret; } #************************************************ # 関数名:setHtmlcode # 内容:最終的に書き出すHTMLを整形 # 引数:本文、ファイル名、ファイルパス($src, $filename, $filepath) # 戻り値:文字列(HTMLソースコード) #************************************************ sub setHtmlcode { my ( $head, $foot, $htmltitle, $subinfo, $ltime ); my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) = localtime; $htmltitle = ( $donotusepathflag ? $doctitle : "Preview : $_[1]" ); $subinfo = ( $author ? $author . " " : "" ); $subinfo .= ( $donotusepathflag ? "" : "[$_[2]] " ); $year += 1900; $mon++; $ltime = "$year/$mon/$mday $hour:$min:$sec"; $subinfo .= " ($ltime)"; if ($wrn) { ($wrnalert = $wrn) =~ s/\n/\\n/mg; $wrnalert = "alert(\"$wrnalert\");"; } else { $wrnalert = ""; } # HTMLヘッダ初期化 $head = < $htmltitle

$doctitle

$subinfo
×
EOM # HTMLフッタ初期化 $foot = <
200%       ▶︎ 0%
 
$docinfo
$idxsrc
EOM return $head . $_[0] . $foot; }