WEBで入力されたテキストをPDFファイルへ変換する(ASP.NET)
WEBで入力されたテキストをPDFファイルへ変換する事のできるASP.NETのソースコードです。クラスになっていますのでそのまま使用できます
ソースコード
8年以上前に作成した古いコードで私すら覚えていないのですが、何かのお役に立てると嬉しいです。
'------------------------------------------------------- ' PDFWriter for .NET Version ' ' ' 2007.10.6 v0.1 初版完成(Delphiから移植) '------------------------------------------------------- Imports System Imports System.IO Imports System.IO.Compression Imports System.Collections.Generic Namespace papy.library ' 用紙サイズ列挙体 Public Enum Enum_PrintSize A3 ' A3 842x1191 297x420mm A4 ' A4 595x842 210x297mm A5 ' A5 420x595 148x210mm B4 ' B4 729x1032 257x364mm B5 ' B5 516x729 182x257mm End Enum ' PDF Writer用の例外 Public Class PDFMaxSizeException Inherits ApplicationException Public Sub New(ByVal ErrorMessage As String) MyBase.New(ErrorMessage) End Sub End Class ' PDFオブジェクト管理 Public Class PDFObjMemManager Private Hash As New Dictionary(Of String, UInt32) Private FObjectIndex As UInt32 Public Sub New() FObjectIndex = 0 End Sub Public Property ObjectIndex() As UInt32 Get Return FObjectIndex End Get Set(ByVal value As UInt32) FObjectIndex = value End Set End Property Public ReadOnly Property ObjectPosArray(ByVal index As UInt32) As UInt32 Get Return Hash(index.ToString) End Get End Property Public Sub SetObjectPosArray(ByVal index As UInt32, ByVal Pos As UInt32) Hash.Add(index.ToString, Pos) End Sub End Class ' PDF作成クラス Public Class PDFWriter Private Stream, MemStream As MemoryStream Private ObjectMem As PDFObjMemManager Private StringList As ArrayList Private FMaxFilesize As Integer ' 読み込める最大バイト数 Private FFontSize As Byte ' フォントのサイズ (1-100ぐらいまで) Private FPrintSize As Enum_PrintSize ' 用紙のサイズ Private FPageWidth ' 用紙の横サイズ Private FPageHeight ' 用紙の縦サイズ Private FMarginX As Byte ' 余白 (← →) Private FMarginY As Byte ' 余白 (↑ ↓) Private Const m_FontName = "F0" ' フォントの変数名 Private Const m_FontEncoding = "90ms-RKSJ-H" ' フォントのエンコーディング" Private Const m_FontWidth = "231 389 500 631 631 500" ' 1byteフォントの幅" '''' <summary> '''' コンストラクタ(フォントサイズ、余白サイズ、ページサイズ、読込最大バイト数を可能です) '''' </summary> ''' <param name="FontSize">フォントのサイズ 1-100ぐらいまで</param> ''' <param name="PrintSize">用紙のサイズ A3,A4,A5,B4,B5</param> ''' <param name="MarginX">余白 (← →)</param> ''' <param name="MarginY">余白 (↑ ↓)</param> ''' <param name="MaxFilesize">読み込める最大バイト数</param> ''' <remarks></remarks> Public Sub New(Optional ByVal FontSize As Byte = 12, _ Optional ByVal PrintSize As Enum_PrintSize = Enum_PrintSize.A4, _ Optional ByVal MarginX As Byte = 30, _ Optional ByVal MarginY As Byte = 30, _ Optional ByVal MaxFilesize As Integer = 3000000) Stream = New System.IO.MemoryStream ObjectMem = New PDFObjMemManager StringList = New ArrayList FFontSize = FontSize FPrintSize = PrintSize FMarginX = MarginX FMarginY = MarginY FMaxFilesize = MaxFilesize Select Case PrintSize Case Enum_PrintSize.A3 : FPageWidth = 842 : FPageHeight = 1191 Case Enum_PrintSize.A4 : FPageWidth = 595 : FPageHeight = 842 Case Enum_PrintSize.A5 : FPageWidth = 420 : FPageHeight = 595 Case Enum_PrintSize.B4 : FPageWidth = 729 : FPageHeight = 1032 Case Enum_PrintSize.B5 : FPageWidth = 516 : FPageHeight = 729 End Select End Sub ''' <summary> ''' 読み込める最大バイト数 ''' </summary> Public Property MaxFilesize() As Integer Get Return FMaxFilesize End Get Set(ByVal value As Integer) FMaxFilesize = value End Set End Property ''' <summary> ''' フォントのサイズ 1-100ぐらいまで ''' </summary> Public Property FontSize() As Byte Get Return FFontSize End Get Set(ByVal value As Byte) If (value >= 1) And (value <= 100) Then FFontSize = value Else End If End Set End Property ''' <summary> ''' プリントのサイズ A3,A4,A5,B4,B5 ''' </summary> Public Property PrintSize() As Enum_PrintSize Get Return FPrintSize End Get Set(ByVal value As Enum_PrintSize) FPrintSize = value Select Case value Case Enum_PrintSize.A3 : FPageWidth = 842 : FPageHeight = 1191 Case Enum_PrintSize.A4 : FPageWidth = 595 : FPageHeight = 842 Case Enum_PrintSize.A5 : FPageWidth = 420 : FPageHeight = 595 Case Enum_PrintSize.B4 : FPageWidth = 729 : FPageHeight = 1032 Case Enum_PrintSize.B5 : FPageWidth = 516 : FPageHeight = 729 End Select End Set End Property ''' <summary> ''' 余白の横(←→)サイズ ''' </summary> Public Property MarginX() As Byte Get Return FMarginX End Get Set(ByVal value As Byte) FMarginX = value End Set End Property ''' <summary> ''' 余白の縦(↑↓)サイズ ''' </summary> Public Property MarginY() As Byte Get Return FMarginY End Get Set(ByVal value As Byte) FMarginY = value End Set End Property ' 文字列の書き込み Private Sub WriteString(ByVal AString As String) Dim pByteArray As Byte() = System.Text.Encoding.GetEncoding("Shift-JIS").GetBytes(AString) Stream.Write(pByteArray, 0, pByteArray.Length) End Sub ' クロスリファレンステーブル Private Sub Write_CrossReferenceTable() Dim i As Integer WriteString("xref" & vbLf) WriteString(String.Format("0 {0}" & vbLf, ObjectMem.ObjectIndex + 1)) WriteString("0000000000 65535 f " & vbLf) For i = 0 To ObjectMem.ObjectIndex - 1 WriteString(String.Format("{0:0000000000}", ObjectMem.ObjectPosArray(i)) & " 00000 n " & vbLf) Next End Sub ' 文字列を16進表記で保存する(高速) Private Overloads Sub AsciiHexEncoding(ByRef AString As String) Dim pByteArray As Byte() = System.Text.Encoding.GetEncoding("Shift-JIS").GetBytes(AString) Dim i As Integer WriteString("<") For i = 0 To pByteArray.Length - 1 ' 改行をわざと無視する(ポイント) If (pByteArray(i) = 13 Or pByteArray(i) = 10) Then Continue For End If WriteString(pByteArray(i).ToString("X2")) Next WriteString(">") End Sub ' 文字列を16進表記で保存する(低速) Private Overloads Sub AsciiHexEncoding(ByRef PByteArray() As Byte, ByVal Size As UInt32) Dim i As Integer WriteString("<") For i = 0 To Size - 1 If PByteArray(i) = 13 Or PByteArray(i) = 10 Then Continue For End If WriteString(Convert.ToString(PByteArray(i), 16)) Next WriteString(">") End Sub ' テキストの描画 Private Sub DrawText(ByVal x As Integer, ByVal y As Integer, ByRef PageText As ArrayList) Dim i As UInt32 Dim Matrix As Single If PageText.Count = 0 Then Exit Sub y = FPageHeight - y Matrix = y - FontSize * 0.87 ' 描画オブジェクト WriteString("BT" & vbLf) WriteString(String.Format("/{0} {1} Tf" & vbLf, m_FontName, FontSize)) WriteString(String.Format("0 0 0 rg {0} TL {1} {2} Td ", FontSize, x, Matrix)) ' 文字列の書き込み AsciiHexEncoding(PageText(0)) WriteString(" Tj" & vbLf) ' 2行以上ある場合 If PageText.Count <> 1 Then For i = 1 To PageText.Count - 1 WriteString("T* ") AsciiHexEncoding(PageText(i)) WriteString(" Tj" & vbLf) Next End If WriteString("ET" & vbLf) End Sub ' テキストの横幅を取得する Private Function GetTextWidth(ByVal S As String) As Integer Return (System.Text.Encoding.GetEncoding("Shift_JIS").GetByteCount(S) _ * (FontSize / 2)) End Function ' テキストの行数を整える Private Sub AutoLineFeed() Dim P As Byte() Dim S As String Dim Sjis(1) As Byte Dim i, j, MaxWidth As Integer Dim List As ArrayList = New ArrayList Dim Lines As ArrayList = StringList MaxWidth = FPageWidth - FMarginX * 2 For i = 0 To Lines.Count - 1 ' テキストがページの描画範囲を越える場合は改行する If GetTextWidth(Lines(i).ToString) > MaxWidth Then S = "" : j = 0 P = System.Text.Encoding.GetEncoding("Shift-JIS").GetBytes(Lines(i).ToString & Chr(0)) While Not (P(j) = 0) ' Sjis漢字コード (2byteなので二文字足す) If (P(j) >= &H81 And P(j) <= &H9F) Or _ (P(j) >= &HE0 And P(j) <= &HFC) Then ' [一文字目] Sjis(0) = P(j) : j += 1 ' Sjisで文字が途中の場合は無視する If (j >= P.Length - 1) OrElse P(j) = 0 Then Continue While ' [二文字目] Sjis(1) = P(j) ' SjisからUnicode変換 Sjis = System.Text.Encoding.Convert(Encoding.GetEncoding("Shift-JIS"), Encoding.Unicode, Sjis) S = S & Encoding.Unicode.GetString(Sjis) ' 描画サイズを超える場合は改行 If GetTextWidth(S) > MaxWidth - (FontSize) Then List.Add(S) S = "" End If ' Ascii + 半角カタカナなど Else S = S & Chr(P(j)) If GetTextWidth(S) > MaxWidth - (FontSize / 2) Then List.Add(S) S = "" End If End If j += 1 End While If S <> "" Then List.Add(S) End If Else List.Add(Lines(i).ToString) End If Next Lines.Clear() Lines.AddRange(List) End Sub ' PDFページオブジェクトの書き込み Private Sub Write_PageObject(ByRef PageList As ArrayList) Dim PageText As ArrayList = New ArrayList Dim i, j, k, Pages, Streamsize, MaxHeight, PageRows As Integer ' テキストの自動整形 AutoLineFeed() ' 1ページで描画可能なサイズ MaxHeight = FPageHeight - FMarginY * 2 ' 1ページに入る配列数 PageRows = StringList.Count For i = 1 To StringList.Count If MaxHeight <= i * FontSize Then PageRows = i - 1 Exit For End If Next ' ページ数の計算 If StringList.Count <> 0 Then Pages = (StringList.Count \ PageRows) If (StringList.Count - PageRows) <> 0 Then Pages += 1 End If Else Pages = 1 End If k = 0 For i = 0 To Pages - 1 ' 1ページ分の配列を受け取る PageText.Clear() For j = 0 To PageRows - 1 If k >= StringList.Count Then Continue For PageText.Add(StringList(k).ToString) k += 1 Next '' 2ページ以降の先頭は改行コードを挿入 'If i >= 1 Then ' PageText.Insert(0, "") 'End If ' Kids Page PageList.Add((ObjectMem.ObjectIndex + 1).ToString) ObjectMem.SetObjectPosArray(ObjectMem.ObjectIndex, Stream.Position) WriteString(String.Format("{0} 0 obj" & vbLf, ObjectMem.ObjectIndex + 1)) WriteString("<<" & vbLf) WriteString("/Type /Page" & vbLf) WriteString("/Parent 2 0 R" & vbLf) WriteString("/Resources" & vbLf) WriteString("<<" & vbLf) WriteString(String.Format("/Font << /{0} 3 0 R >>" & vbLf, m_FontName)) WriteString("/ProcSet [ /PDF /Text ]" & vbLf) WriteString(">>" & vbLf) WriteString(String.Format("/MediaBox [ 0 0 {0} {1} ]" & vbLf, FPageWidth, FPageHeight)) WriteString(String.Format("/Contents {0} 0 R" & vbLf, ObjectMem.ObjectIndex + 2)) WriteString(">>" & vbLf) WriteString("endobj" & vbLf) ObjectMem.ObjectIndex += 1 ' Contents Object ObjectMem.SetObjectPosArray(ObjectMem.ObjectIndex, Stream.Position) WriteString(String.Format("{0} 0 obj" & vbLf, ObjectMem.ObjectIndex + 1)) WriteString(String.Format("<< /Length {0} 0 R >>" & vbLf, ObjectMem.ObjectIndex + 2)) WriteString("stream" & vbLf) ' stream Streamsize = Stream.Position DrawText(FMarginX, FMarginY, PageText) Streamsize = Stream.Position - Streamsize WriteString("endstream" & vbLf) WriteString("endobj" & vbLf) ObjectMem.ObjectIndex += 1 ' Length Object ObjectMem.SetObjectPosArray(ObjectMem.ObjectIndex, Stream.Position) WriteString(String.Format("{0} 0 obj" & vbLf, ObjectMem.ObjectIndex + 1)) WriteString(String.Format("{0}" & vbLf, Streamsize)) WriteString("endobj" & vbLf) ObjectMem.ObjectIndex += 1 Next End Sub Private Sub __txt2pdf(ByVal SaveFileName As String) Dim i As Integer Dim PageList As ArrayList = New ArrayList ' 最初のヘッダ部分は後で書き込む ObjectMem.ObjectIndex = 2 ' PDF version WriteString("%PDF-1.2" & vbLf) ' Font リソース ObjectMem.SetObjectPosArray(ObjectMem.ObjectIndex, Stream.Position) WriteString(String.Format("{0} 0 obj" & vbLf, ObjectMem.ObjectIndex + 1)) WriteString("<<" & vbLf) WriteString("/Type /Font" & vbLf) WriteString(String.Format("/Name /{0}" & vbLf, m_FontName)) WriteString(String.Format("/BaseFont /HeiseiKakuGo-W5-{0}" & vbLf, m_FontEncoding)) WriteString("/Subtype /Type0" & vbLf) WriteString(String.Format("/Encoding /{0}" & vbLf, m_FontEncoding)) WriteString("/DescendantFonts [ << /Type /Font /Subtype /CIDFontType0 /BaseFont /HeiseiKakuGo-W5" & vbLf) WriteString("/FontDescriptor << /Type /FontDescriptor /FontName /HeiseiKakuGo-W5 /ItalicAngle 0") WriteString("/FontBBox [ -92 -250 1010 922 ]" & vbLf) WriteString("/Style << /Panose <") WriteString("0801020B0600000000000000") WriteString(">>> /Ascent 752 /CapHeight 737 /Descent -221" & vbLf) WriteString("/Flags 4 /StemV 114 /XHeight 553 >>" & vbLf) WriteString("/CIDSystemInfo << /Registry (Adobe)/Ordering (Japan1)/Supplement 2 >>" & vbLf) WriteString(String.Format("/DW 1000 /W [ {0} ] >>" & vbLf, m_FontWidth)) WriteString("]" & vbLf) WriteString(">>" & vbLf) WriteString("endobj" & vbLf) ObjectMem.ObjectIndex += 1 ' Write Page Write_PageObject(PageList) ' Catalog ObjectMem.SetObjectPosArray(0, Stream.Position) WriteString("1 0 obj" & vbLf) WriteString("<<" & vbLf) WriteString("/Type /Catalog" & vbLf) WriteString("/Pages 2 0 R" & vbLf) WriteString(">>" & vbLf) WriteString("endobj" & vbLf) ' Parent Pages ObjectMem.SetObjectPosArray(1, Stream.Position) WriteString("2 0 obj" & vbLf) WriteString("<<" & vbLf) WriteString("/Type /Pages" & vbLf) ' Kids Pages WriteString("/Kids [") For i = 0 To PageList.Count - 1 WriteString(String.Format(" {0} 0 R", PageList(i).ToString)) Next WriteString(" ]" & vbLf) WriteString(String.Format("/Count {0}" & vbLf, PageList.Count)) WriteString(">>" & vbLf) WriteString("endobj" & vbLf) ' CrossReferenceTable ObjectMem.SetObjectPosArray(ObjectMem.ObjectIndex, Stream.Position) Write_CrossReferenceTable() ' trailer WriteString("trailer" & vbLf) WriteString("<<" & vbLf) WriteString(String.Format("/Size {0}" & vbLf, ObjectMem.ObjectIndex + 1)) WriteString("/Root 1 0 R" & vbLf) WriteString(">>" & vbLf) WriteString("startxref" & vbLf) WriteString(String.Format("{0}" & vbLf, ObjectMem.ObjectPosArray(ObjectMem.ObjectIndex))) WriteString("%%EOF") ' ファイルへ保存 If (Not SaveFileName.Equals("")) AndAlso (MemStream Is Nothing) Then Dim fs As FileStream = New FileStream(SaveFileName, FileMode.Create) fs.Write(Stream.ToArray, 0, Stream.Length) fs.Close() Else ' ストリームへ書き込み MemStream.Write(Stream.ToArray, 0, Stream.Length) End If End Sub ''' <summary> ''' テキストからPDFファイルを作成する(文字列から読み込み/ファイルへ保存) ''' </summary> ''' <param name="AString">テキスト</param> ''' <param name="SaveFileName">保存する場所</param> Public Sub txt2pdf(ByVal AString As String, ByVal SaveFileName As String) Dim pByteArray As Byte() = Encoding.GetEncoding("Shift-JIS").GetBytes(AString) txt2pdf(pByteArray, SaveFileName) End Sub ''' <summary> ''' テキストからPDFファイルを作成する(文字列から読み込み/ストリームへ保存) ''' </summary> ''' <param name="AString">テキスト</param> ''' <param name="SaveStream">保存する場所</param> Public Sub txt2pdf(ByVal AString As String, ByRef SaveStream As MemoryStream) MemStream = SaveStream txt2pdf(AString, "") End Sub ''' <summary> ''' テキストからPDFファイルを作成する(バイト配列から読み込み/ファイルへ保存) ''' </summary> ''' <param name="pByteArray">テキストがあるバイト配列</param> ''' <param name="SaveFileName">保存する場所</param> Public Sub txt2pdf(ByRef pByteArray As Byte(), ByVal SaveFileName As String) ' ファイルのサイズが規定以上ならばエラーを発生する If pByteArray.Length > MaxFilesize Then Throw New PDFMaxSizeException("文字が " & Format(MaxFilesize, "#,###") & "Byte を超えています。") End If Dim i, cnt As Integer Dim PrePos As Integer = 0 Dim vblf_flg As Boolean = False Dim rast_flg As Boolean = True For i = 0 To pByteArray.Length - 1 ' CRの続きにLFがある場合はスキップ If vblf_flg Then vblf_flg = False Continue For End If ' 最終フラグとカウンタ増加 rast_flg = False : cnt += 1 ' CR/LF改行コードならば If (pByteArray(i) = 13) Or (pByteArray(i) = 10) Then ' 次のコードがLFの場合 If i + 1 <= pByteArray.Length - 1 Then If pByteArray(i + 1) = 10 Then StringList.Add(Encoding.GetEncoding("Shift-JIS").GetString(pByteArray, PrePos, cnt)) PrePos = PrePos + cnt + 1 cnt = 0 : vblf_flg = True : rast_flg = True Continue For End If End If StringList.Add(Encoding.GetEncoding("Shift-JIS").GetString(pByteArray, PrePos, cnt)) PrePos = PrePos + cnt cnt = 0 : rast_flg = True End If Next ' 文字列の最後が改行コードで終了していない場合 If Not rast_flg Then StringList.Add(Encoding.GetEncoding("Shift-JIS").GetString(pByteArray, PrePos, cnt)) End If __txt2pdf(SaveFileName) End Sub ''' <summary> ''' テキストからPDFファイルを作成する(バイト配列から読み込み/ストリームへ保存) ''' </summary> ''' <param name="pByteArray">テキストがあるバイト配列</param> ''' <param name="SaveStream">保存するストリーム</param> Public Sub txt2pdf(ByRef pByteArray As Byte(), ByRef SaveStream As MemoryStream) MemStream = SaveStream txt2pdf(pByteArray, "") End Sub ''' <summary> ''' テキストからPDFファイルを作成する( ストリームから読み込み/ファイルへ保存) ''' </summary> ''' <param name="AStream">テキストがあるストリーム</param> ''' <param name="SaveFileName">保存する場所</param> Public Sub txt2pdf(ByVal AStream As Stream, ByVal SaveFileName As String) ' メモリに読み込む Dim pByteArray(AStream.Length) As Byte AStream.Read(pByteArray, 0, AStream.Length) Dim AString As String = Encoding.GetEncoding("Shift-JIS").GetString(pByteArray) txt2pdf(AString, SaveFileName) End Sub ''' <summary> ''' テキストからPDFファイルを作成する(ストリームから読み込み/ストリームへ保存) ''' </summary> ''' <param name="AStream">テキストがあるストリーム</param> ''' <param name="SaveStream">保存する場所</param> Public Sub txt2pdf(ByVal AStream As Stream, ByRef SaveStream As MemoryStream) MemStream = SaveStream txt2pdf(AStream, "") End Sub End Class End Namespace
クラスの利用方法
Imports System.io Imports papy.library Partial Class txt2pdf Inherits System.Web.UI.UserControl Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click TextBox1.Text = "" End Sub Protected Sub Button2_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button2.Click Dim Stream As MemoryStream = New MemoryStream() Dim test As PDFWriter = New PDFWriter Try test.txt2pdf(TextBox1.Text, Stream) Catch ex As Exception Response.Clear() Response.ContentType = "text/html" Response.Write(ex.Message) Response.End() Exit Sub End Try Response.Clear() Response.ContentType = "application/pdf" Response.AddHeader("content-disposition", "attachment; filename=txt2pdf.pdf") Response.BinaryWrite(Stream.ToArray) Stream.Flush() : Stream.Close() Response.End() End Sub End Class
スポンサーリンク
関連記事
公開日:2015年02月18日
記事NO:00237