- PR -

動的なPDFファイルの作成

1
投稿者投稿内容
Totti
会議室デビュー日: 2004/06/24
投稿数: 10
投稿日時: 2004-11-22 11:50
 お世話になります。現在、ASP.Net、VisualStudio2003の環境で、C#を使用した
Webアプリを作成しております。今やりたいことは、クライアント側に表示されて
いるWebフォーム上で、任意の検索条件を指定し、ボタンを押すことにより、検索
条件に合致するデータをDBから取得し、そのデータを元にPDFファイルをサーバー
上に作成し、その後すぐにクライアント側にダウンロードのダイアログを表示した
いのですが、その方法が分かりません。DBから取得したデータを元にPDFを表示するだ
けなら、現在FDFを使用して実現可能となっております。また、DBから取得したデ
ータを元にExcelファイルをサーバーに作成し、クライアント側にダイアログを出
すことも実現可能となっております。サーバーにAcrobatを入れれば実現可能とい
うことを聞きましたが、今回はなるべくサーバーにAcrobatを入れないで、かつ商
用のライブラリなどを使用しない(=お金を全くかけないで)PDFを作成する方法を調
査しております。FDFのみでは実現不可能といった話も耳にしました。どなたかご存
知の方がおりましたらご教示いただければと思います。
とっちん
会議室デビュー日: 2004/11/22
投稿数: 18
投稿日時: 2004-11-22 20:23
はじめまして。
以前私もTottiさんと同じような開発を行いました。
そのときはiTextSharpを使用してブラウザ上で非同期にPDFファイルを生成させました。
罫線つきのテーブルも結構簡単に組めますよ。

http://homepage3.nifty.com/dotnetfan/tool/tool02.html

http://itextsharp.sourceforge.net/index.html
Totti
会議室デビュー日: 2004/06/24
投稿数: 10
投稿日時: 2004-11-26 16:21
とっちんさん、ご返答まことにありがとうございます。そして返信が遅くなり、大変申し訳ありませんでした。とっちんさんの言うように、iTextSharpで行うのがベストかなと思い、iTextSharpを使用してコーディングを行おうと思ったのですが、前回書き込みさせていただいた内容には記載しませんでしたが、今回行いたいのはフォーマットが決まっているPDFファイルに値を埋め込むといったことをやりたいのですが、iTextSharpのサイトなどに記載されておりますチュートリアルを見てもそれらしきことは載っていませんでした。(何分英文のチュートリアルなので、英語力のない私が見落としているだけかもしれませんが(^^)iTextSharpで既存のPDFファイルを読み込み、それに対して任意の場所に文字を表示させ、それが完了したらPDFファイルに別名をつけて保存する、といったことはiTextSharpでは不可能なのでしょうか。(現在退避策として考えているのが、同じフォーマットのExcelを読み込み、それに値を埋め込んだ後別名をつけて保存し、再度Excelファイル(値が埋め込まれている)を読み込んで、あらかじめExcelに登録してあるマクロを自動起動させるorC#からExcelマクロを実行する、といった方法を考えております)
がるがる
ぬし
会議室デビュー日: 2002/04/12
投稿数: 873
投稿日時: 2004-11-26 16:33
どもです。がるです。
ちっと蛇足ちっくなお話で恐縮なのですが。

引用:

Tottiさんの書き込み (2004-11-22 11:50) より:
クライアント側に表示されて
いるWebフォーム上で、任意の検索条件を指定し、ボタンを押すことにより、検索
条件に合致するデータをDBから取得し、そのデータを元にPDFファイルをサーバー
上に作成し、その後すぐにクライアント側にダウンロードのダイアログを表示した
いのですが


んっと。この手のは気をつけないとセキュリティホールになると
思います。
Tottiさんがおっしゃってる手順は

データを入力->
            DBから該当データを取得
            PDFファイルを作成
           <-PDFファイルを指し示す識別子を含むURLを返却
URLをクリック->
           <-PDFファイルを出力
PDFファイルをゲット

って感じだとおもうのですが。これだと、URLを適当に
偽装されたり総アタックかけられたりすると、他人のPDFが
getできてしまう可能性があります。

可能なら

データを入力->
            DBから該当データを取得
            PDFファイルを作成
           <-PDFファイルを出力
PDFファイルをゲット

という流れで、実ファイルを作らないようにしたほうがより
安全かなぁ、と思います。

蛇足ですが。



とっちん
会議室デビュー日: 2004/11/22
投稿数: 18
投稿日時: 2004-11-26 20:52
こんにちは。
iTextSharpは基本的に動的にPDFを生成するもののようですね。

がるがるさんのご指摘ももっともですし、できればフォーマットも含め動的に生成する方がスマート(ではないかも?)ではないでしょうか。
Tottiさんのフォーマットとは複雑なものなのでしょうか?

例えば、
iTextSharp.textとiTextSharp.text.pdfをbinに配置しImportします。
DBから取得したデータはDataTable(tbl)に格納してあるものとします。
Dim ds As System.Data.DataSet
ds = New System.Data.DataSet("pdfds")
Dim tbl As System.Data.DataTable = ds.Tables.Add("pdftbl")
Dim row As System.Data.DataRow
'商品か何かのコード
tbl.Columns.Add("id", System.Type.GetType("System.Int32"))
'商品か何かの名前
tbl.Columns.Add("name", System.Type.GetType("System.String"))
'売上年月(200412と200312)
tbl.Columns.Add("yym", System.Type.GetType("System.Int32"))
'売上週(1〜5)
tbl.Columns.Add("week", System.Type.GetType("System.Int32"))
'売上数量
tbl.Columns.Add("suryo", System.Type.GetType("System.Double"))

'データテーブルのソート処理
Dim resultrow() As System.Data.DataRow
Dim rowx As System.Data.DataRow
resultrow = tbl.Select("", "id")
'PDFドキュメント生成処理
Dim doc As new Document(PageSize.A3.rotate(), 30, 30, 30, 30)
Dim strpdfpath As String = "c:\inetpub\wwwroot\test\test.pdf"
Try
  Dim w As PdfWriter
  w = PdfWriter.getinstance(doc, new FileStream(strpdfpath, FileMode.Create))
  Dim bf As BaseFont = BaseFont.CreateFont("c:\\windows\\fonts\\msgothic.ttc, 0", _
                        BaseFont.IDENTITY_H, _
                        BaseFont.EMBEDDED)
  Dim gtfont As Font = new Font(bf, 9, Font.NORMAL)
  Dim headertxt As String
  Dim dt As DateTime = DateTime.Now()
  Dim strdate As String = dt.ToString("yy/MM/dd")
  Dim strtime As String = dt.ToString("HH:mm:ss")
  headertxt = "【 タイトル2004年12月 前年対比 】" & _
        strdate & " " & strtime & " Page : "
  Dim header As HeaderFooter = new HeaderFooter(new Phrase(headertxt, gtfont), true)
  header.Border = Rectangle.NO_BORDER
  doc.Header = header
  doc.Open()
  'PDF出力用ワーク変数宣言
  Dim dblsuryo(1, 5) As Double
  Dim intid As Integer
  Dim strname As String
  Dim strvalue As String
  Dim dblvalue As Double
  Dim dblp1 As Double
  Dim dblp2 As Double
  Dim intline As Integer = 0
  Dim i As Integer = 0
  Dim j As Integer
  Dim k As Integer
  'PDFテーブル設定
  Dim itbl As iTextSharp.text.Table
  itbl = new iTextSharp.text.Table(19)
  Dim headerwidth As Single() = _
  {10, 5.5, 5.5, 4, 5.5, 5.5, 4, 5.5, 5.5, 4, 5.5, 5.5, 4, 5.5, 5.5, 4, 5.5, 5.5, 4}
  itbl.Widths = headerwidth
  itbl.WidthPercentage = 100
  '※手動で罫線を引く場合には0を指定
  itbl.DefaultCellBorderWidth = 1
  itbl.Padding = 0
  itbl.Spacing = 1
  'データテーブルをループしPDF出力
  For Each rowx In resultrow
    If i = 0 Then
      '配列初期化
      For j = 0 To 1
        For k = 0 To 5
          dblsuryo(j, k) = 0
        Next
      Next
      '比較用変数セット
      intid = CType(rowx("id"), Integer)
      strname = CType(rowx("name"), String)
      i = 1
    End If
    'idが変わった場合
    If intid <> CType(rowx("id"), Integer) Then
      'ヘダー出力
      itbl.DefaultHorizontalAlignment = Element.ALIGN_CENTER
      itbl.DefaultColspan = 1
      itbl.DefaultRowspan = 2
      itbl.addCell(new Phrase("商品", gtfont))
      itbl.DefaultColspan = 3
      itbl.DefaultRowspan = 1
      itbl.addCell(new Phrase("第1週", gtfont))
      itbl.addCell(new Phrase("第2週", gtfont))
      itbl.addCell(new Phrase("第3週", gtfont))
      itbl.addCell(new Phrase("第4週", gtfont))
      itbl.addCell(new Phrase("第5週", gtfont))
      itbl.addCell(new Phrase("合計", gtfont))
      itbl.DefaultColspan = 1
      itbl.DefaultRowspan = 1
      itbl.addCell(new Phrase("当年実績", gtfont))
      itbl.addCell(new Phrase("前年実績", gtfont))
      itbl.addCell(new Phrase("前年比", gtfont))
      itbl.addCell(new Phrase("当年実績", gtfont))
      itbl.addCell(new Phrase("前年実績", gtfont))
      itbl.addCell(new Phrase("前年比", gtfont))
      itbl.addCell(new Phrase("当年実績", gtfont))
      itbl.addCell(new Phrase("前年実績", gtfont))
      itbl.addCell(new Phrase("前年比", gtfont))
      itbl.addCell(new Phrase("当年実績", gtfont))
      itbl.addCell(new Phrase("前年実績", gtfont))
      itbl.addCell(new Phrase("前年比", gtfont))
      itbl.addCell(new Phrase("当年実績", gtfont))
      itbl.addCell(new Phrase("前年実績", gtfont))
      itbl.addCell(new Phrase("前年比", gtfont))
      itbl.addCell(new Phrase("当年実績", gtfont))
      itbl.addCell(new Phrase("前年実績", gtfont))
      itbl.addCell(new Phrase("前年比", gtfont))
      '明細出力
      itbl.DefaultColspan = 1
      itbl.DefaultRowspan = 1
      strvalue = CType(intid, String) & " : " & strname
      itbl.DefaultHorizontalAlignment = Element.ALIGN_LEFT
      itbl.addCell(new Phrase(strvalue, gtfont))
      itbl.DefaultHorizontalAlignment = Element.ALIGN_RIGHT
      For k = 0 To 5
         For j = 0 To 1
            strvalue = Format(dblsuryo(j, k), "#,##0")
            itbl.addCell(new Phrase(strvalue, gtfont))
         Next
         dblp1 = 0
         dblp2 = 0
         '前年比
         If dblsuryo(0, k) <> 0 and _
            dblsuryo(1, k) <> 0 Then
            dblvalue = dblsuryo(0, k) / dblsuryo(1, k) * 100
            dblp1 = Math.Floor(dblvalue * 10 + 0.5)
            dblp2 = dblp1 * 0.1
         End If
         If dblp2 = 0 or dblp2 > 9999 Then
            strvalue = "-----"
         Else
            strvalue = Format(dblp2, "#,##0.0") & "%"
         End If
         itbl.addCell(new Phrase(strvalue, gtfont))
      Next
      '配列初期化
      For j = 0 To 1
         For k = 0 To 5
            dblsuryo(j, k) = 0
         Next
      Next
      '比較用変数セット
      intid = CType(rowx("id"), Integer)
      strname = CType(rowx("name"), String)
    End If
    If intline >= 12 Then
       '改ページ処理
       doc.Add(itbl)
       doc.newPage()
       intline = 0
       'PDFテーブル設定
       itbl = new iTextSharp.text.Table(19)
       itbl.Widths = headerwidth
       itbl.WidthPercentage = 100
       '※手動で罫線を引く場合には0を指定
       itbl.DefaultCellBorderWidth = 1
       itbl.Padding = 0
       itbl.Spacing = 1
    End If
    '配列格納処理
    If CType(rowx("yym"), Integer) = 200412 Then
       j = 0
    Else
       j = 1
    End If
    k = CType(rowx("week"), Integer) - 1
    '数量集計処理
    dblsuryo(j, k) += CType(rowx("suryo"), Integer)
    dblsuryo(j, 6) += CType(rowx("suryo"), Integer)
  Next
  'idが変わった場合と同じ処理
  '(中略)
  doc.Add(itbl)
Catch de As DocumentException
  Return -1
  Exit Function
Catch ioe As IOException
  Return -1
  Exit Function
Catch ex As Exception
  Return -1
  Exit Function
Finally
  doc.Close()
End Try

こんな感じでDBから読み込んだデータを罫線つきで出力できます。
もっと複雑なフォーマットで罫線を自分で引きたい場合には、
Dim intx As Integer
Dim inty As Integer
Dim cb As PdfContentByte = w.DirectContent
'縦外枠&区切り線出力
cb.LineWidth = 2
intx = 30
inty = 813
cb.moveTo(intx, inty)
cb.lineTo(intx, 417)
intx = 112
cb.moveTo(intx, inty)
cb.lineTo(intx, 417)
For i = 0 To 8
  cb.moveTo(intx, inty)
  cb.lineTo(intx, 417)
  intx += 131
Next
cb.stroke()
'縦区切り線出力
cb.LineWidth = 1
intx = 164
inty = 813
cb.moveTo(intx, inty)
cb.lineTo(intx, 417)
For i = 0 To 7
  cb.moveTo(intx, inty)
  cb.lineTo(intx, 417)
  intx += 39
  cb.moveTo(intx, inty)
  cb.lineTo(intx, 417)
  intx += 92
Next
cb.stroke()
'横太枠区切り線出力
cb.LineWidth = 2
intx = 30
inty = 813
cb.moveTo(intx, inty)
cb.lineTo(1160, inty)
inty = inty - 11
For i = 0 To 35
  If i = 0 or i = 1 or i = 4 or _
   i = 5 or i = 13 or _
   i = 20 or i = 24 or _
   i = 27 or i = 35 Then
   cb.moveTo(intx, inty)
   cb.lineTo(1160, inty)
  End If
  inty = inty - 11
Next
cb.stroke()
'横明細区切り線
cb.LineWidth = 1
intx = 30
inty = 813
cb.moveTo(intx, inty)
cb.lineTo(1160, inty)
inty = inty - 11
For i = 0 To 35
  If i <> 0 or i <> 1 or i <> 4 or _
    i <> 5 or i <> 13 or _
    i <> 20 or i <> 24 or _
    i <> 27 or i <> 35 Then
    cb.moveTo(intx, inty)
    cb.lineTo(1160, inty)
  End If
  inty = inty - 11
Next
cb.stroke()

こんな感じでいかがでしょうか?
フリーのソフトなので、このへんが限界かもしれませんね。
1

スキルアップ/キャリアアップ(JOB@IT)