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
プチモンテ ※この記事を書いた人
![]() | |
![]() | 💻 ITスキル・経験 サーバー構築からWebアプリケーション開発。IoTをはじめとする電子工作、ロボット、人工知能やスマホ/OSアプリまで分野問わず経験。 画像処理/音声処理/アニメーション、3Dゲーム、会計ソフト、PDF作成/編集、逆アセンブラ、EXE/DLLファイルの書き換えなどのアプリを公開。詳しくは自己紹介へ |
| 🎵 音楽制作 BGMは楽器(音源)さえあれば、何でも制作可能。歌モノは主にロック、バラード、ポップスを制作。歌詞は抒情詩、抒情的な楽曲が多い。楽曲制作は🔰2023年12月中旬 ~ | |









