
PDFSharpを使用したWPFアプリケーションからのPDFの生成に関する前回の投稿に続く短い投稿。 その記事で説明されているように、生成はFlowDocumentを仲介として使用して行われます。 FlowDocumentでは、 ハイパーリンクを使用してさまざまな種類のハイパーリンクを表示できますが、使用したPDFSharp.Xpsコンバーターのバージョンは、 XpsElement要素に添付されたFixedPage_NavigateUri属性をはっきりと無視していることがわかりました 。
PDF 1.4出力形式を整理するのに少し時間を費やしましたが、これまでのところ、PDFSharp.XpsプロジェクトのPdfContentWriterで印刷を適切に修正する方法を見つけることができませんでした。
カットの下では、よりシンプルなソリューション、すなわちリンク注釈の形式でテキストへのハイパーリンクを課すことが示されています。 また、この記事の最後には、PDF出力プロセスへのプリミティブの導入による、問題に対する「コーシャ」ソリューションのトピックに関する私の研究の結果があります。
リンク注釈を介したソリューション
これが修正されたコミットへのリンクです。 ティーザーが書いたように、 PdfContentWriterコードにリンク注釈の作成を追加しました。 WritePath(...)メソッドでこれを行いました(以下のコードを参照)。
// Checking is there a link attached with this Path if (path.FixedPage_NavigateUri != null && !string.IsNullOrEmpty(path.FixedPage_NavigateUri.Trim())) { var bounds = path.Data.GetBoundingBox(); var xpsPage = path.Parent as FixedPage; if (xpsPage != null) { var pxToPtScale = xpsPage.PointHeight/xpsPage.Height; try { var uri = new Uri(path.FixedPage_NavigateUri); page.AddWebLink( new PdfRectangle(bounds.Left*pxToPtScale, page.Height - bounds.Top*pxToPtScale, bounds.Right*pxToPtScale, page.Height - bounds.Bottom*pxToPtScale), uri.AbsoluteUri); } catch (Exception) { Debug.Assert(false, "WritePath(...) > Invalid URI string provided"); } } }
このコードでは、PDFページに追加されたばかりのPathオブジェクトの境界線を取得し、空でないFixedPage_NavigateUri値を持つパスに対してのみこれを行います。 判明したように、PDFシートの垂直軸はXPSの同じ軸の反対方向に向けられているため、ページの高さからブロック境界の垂直座標を差し引きます。 次に、結果の座標が画面のピクセルからポイントに転送されます。 対応する係数はスクリーンフォントの解像度に依存すると思われるため、動的に計算します。 Pathにアタッチされたリンクは、Uriクラスを介して渡され、リンクが有効であることを確認します。 おそらく、URIを変換するためのより信頼性の高い、効率的な、機能的な方法があります。 今のところ、最も簡単な方法としてこの方法を使用します。 リンクアドレスが無効な場合は、デバッグコンソールにメッセージを書き込むだけです。 ここにログコードを追加することもできます。
このようなパッチを使用したコンバーターの結果は、記事のティーザーの写真に示されています。 リンクの周りの黒い境界線に注意してください。 これは作成されたリンク注釈です。 黒い境界線の存在は、少なくとも作成されたPDFを後処理することで解決できる問題です。 暗号化されていない形式で注釈ブロックマークアップを表示します。
16 0 obj << /タイプ/注釈 / NM(11aabcc9-2402-4718-8184-7ffb9bbb031c) / M(D:20131119233814 + 04'00 ') /サブタイプ/リンク /Rect[81.885 64.185 158.123 50.55] / BS << /タイプ/境界線>> /ボーダー[0 0 0] / A << / S / URI / URI(http://habrahabr.ru/)>> >> endobj
このマークアップでは、テキスト「/ Border [0 0 0]」が色境界のRGBコンポーネントを定義していると思われます。
調査結果
参照注釈による解決策は表面にありました。 唯一の困難は、正しい座標を決定することでした。 しかし、解決策は最善ではありません。 プリミティブ自体の出力を修正し、出力されたPathオブジェクトに注釈の形で松葉杖を押し付けない方がより適切です。 記事の冒頭の写真でわかるように、デフォルトでは、この注釈は見苦しい黒い境界線で表示されます。
そこで、PDF v仕様をダウンロードしました。 1.4 、PDFSharpおよびPDFSharp.Xpsプロジェクトを開き、コードの調査を開始しました。
PdfLinkAnnotationクラスで、次のようなコードに出会いました
internal override void WriteObject(PdfWriter writer) { // ... // switch (this.linkType) { // ... // case LinkType.Web: //pdf.AppendFormat("/A<</S/URI/URI{0}>>\n", PdfEncoders.EncodeAsLiteral(this.url)); Elements[Keys.A] = new PdfLiteral("<</S/URI/URI{0}>>", //PdfEncoders.EncodeAsLiteral(this.url)); PdfEncoders.ToStringLiteral(this.url, PdfStringEncoding.WinAnsiEncoding, writer.SecurityHandler)); break; // ... // }
/ A << / S / URI / URIの行をグーグルで検索すると、 PFの分析ページが表示され、リンクブロックのマークアップのおおよそのビューが表示されました。
6 0オブジェクト << /タイプ/アクション / S / URI / URI(http://stinkeye.org) >> endobj
結果のPDFを開くと、次のことがわかりました。
4 0 obj << /タイプ/ページ / MediaBox [0 0 468 295.98] /親3 0 R /目次5 0 R /リソース << / ProcSet [/ PDF /テキスト/ ImageB / ImageC / ImageI] / ExtGState << / GS0 6 0 R / GS1 15 0 R >> /フォント << / F0 10 0 R / F1 14 0 R >> >> /注釈[16 0 R] /グループ << / CS / DeviceRGB / S /透明性 /虚偽 / K false >> >> endobj
これはページレイアウトユニットです。
5 0 obj << /長さ1114 /フィルター/ FlateDecode >> ストリーム xњYn7}WҐ/$ PђT;Ї ўp} K ‹Zm#@gW+すなわち ..... Ch kCh〜cX„ LA•muw {Yf lgQYyu!A!DBjw $ d'bK¬¦¤D¤ѓ $・A ˜Pђ”:€Ђl2fY <›U`oЎdvђ¶{1ў†zHEЃ o <。 dnWnlyy>\ѕis エンドストリーム endobj
省略記号は、habrahabrのマークアップでサポートされていないテキストを非表示にします。 WinAnsiによってエンコードされた多くの印刷できない文字があります。 コンバーターによって作成されたすべてのPDFプリミティブとUnicodeテキストは、コンバーターに変換されます。つまり、それはバイナリストリームの生のコンテンツです。 したがって、興味深いものはほとんどありません。 デベースに行きましょう。
PdfContentWriter.WritePath(パスパス)にブレークを設定します。 このブレークポイントには、条件を追加します
path.FixedPage_NavigateUri!= null &&!string.IsNullOrEmpty(path.FixedPage_NavigateUri)
もう一度F5を押さないようにします。
テンプレートを解析し、メインウィンドウの[ 印刷 ]ボタンをクリックすると、このブレークポイントに移動し、プリミティブ形式のストリームの内容をテキスト形式で表示できるようになります。 次のテキストのようなものがあります。
q%-BeginContent 0.75 0 0 -0.75 0 295.98 cm -100 Tz q%-グリフを開始 0 0 0 rg / GS0 gs BT / F0 -1 Tf 24 0 0 24 18.18 40.1867 Tm 0 0 Td <002B0048004F004F0052000F0003002B0044004500550044004B0044004500550004> Tj ET Q%-グリフを終了 q%-グリフを開始 0 0 0 rg / GS0 gs BT / F1 -1 Tf 16 0 0 16 18.18 87.3933 Tm 0 0 Td <0028005B005300480055004C005000480051> Tj 4.865 0 Td <0057> Tj 0.34 0 Td <004C0051004A0003005A004C> Tj 2.661 0 Td <0057> Tj 0.34 0 Td <004B000300470052> Tj 1.936 0 Td <0057> Tj 0.34 0 Td <002F004C00540058004C0047000F00030029004F0052005A0027005200460058005000480051> Tj 9.836 0 Td <0057> Tj 0.34 0 Td <000300440051004700030033002700290036004B004400550053> Tj ET Q%-グリフを終了 %...% q%-キャンバスを開始 1 0 0 1 18.18 145.44 cm q%-パスを開始 1 0 0 1 5 10.4533 cm 0 0.204 0.506 rg 5 2.5 m 5 3.88 3.88 5 2.5 5秒 1.12 5 0 3.88 0 2.5秒 0 1.12 1.12 0 2.5 0秒 3.88 0 5 1.12 5 2.5秒 h f * Q%-エンドパス q%-グリフを開始 0 0.204 0.506 rg / GS0 gs BT / F0 -1 Tf 14 0 0 14 20 17.8367 Tm 0 0 Td <002700520046005800500048005100510057000300260052005100570048005B0057> Tj ET Q%-グリフを終了 %...% Q%-キャンバス終了 %...% q%-パスを開始 / GS1 gs 0 0 0 rg 109.18 309.06 101.65 18.18 re f Q%-エンドパス
ここで何が見えますか? PostScript q-Q命令はグラフィカルなコンテキストです。 それらは互いに埋め込まれ、インデントがここで明らかに役割を果たします(はい、確かにこれはすべてPDF形式の仕様にありますが、まだ深く勉強する時間はありません)。 リンクブロックのマークアップをパスマークアップブロックに埋め込む方法
<< /タイプ/アクション / S / URI / URI(http://stinkeye.org) >>
私はまだそれを理解していません。 最も近いレイアウトオプションは、仕様(p。635、例9.14)で見つかりました。
/リンク<< / MCID 1 >>%マーク付きコンテンツシーケンス1(リンク) BDC%マーク付きコンテンツシーケンスの開始 0.7 w%設定線幅 [] 0 d%実線のダッシュパターン 111.094 751.8587 m%下線の先頭に移動 174.486 751.8587 l%下線を引く 0.0 0.0 1.0 RG%ストロークの色を青に設定 S%ストロークの下線 BT%テキストオブジェクトの開始 14 0 0 14 111.094 753.976 Tm%テキストマトリックスの設定 0.0 0.0 1.0 rg%ストロークなしの色を青に設定 (リンク付き)Tj%リンクのテキストを表示 ET%Endテキストオブジェクト EMC%Endマーク付きコンテンツシーケンス
このマークアップでは、「 << / MCID 1 >> 」とは何かを理解できません。 また、このマークアップブロックをどのように、どこに正しく配置するかも明確ではありません。
失敗した修正を実装する際の助けに非常に感謝します。 ご清聴ありがとうございました!