PDFファイルからテキスト化(Azure)C#

PDFファイルを Azure Document Intelligence を利用してテキスト化しました。OCR処理後、テキストボックスに表示されます。アプリの実行フォルダーにテキストデータ(ファイル名は、TEXT )が作成されます。契約形態がフリー(F0)の場合は、ファイルサイズ4MB未満、総ページ数の2ページ目迄です。
Document Intelligence モデルを使用する
Foundry Tools の Azure ドキュメント インテリジェンスは、機械学習を使用してドキュメントから主要なテキストと構造要素を抽出するクラウドベースの Foundry Tools サービスです。 テクノロジを学習するときに、無料サービスを使用することをお勧めします。 無料のページは 1 か月あたり 500 ページに制限されていることに注意してください。
前提条件
Azure サブスクリプション。無料で作成できます。
Foundry Tools またはドキュメント インテリジェンス リソース。 単一サービスまたはマルチサービス。 Free 価格レベル (F0) を使用してサービスを試用し、後から運用環境用の有料レベルにアップグレードすることができます。
アプリケーションを Azure ドキュメント インテリジェンスに接続するために作成するリソースのキーとエンドポイント。

- Azure アカウントと音声リソース:
- 有効な Azure サブスクリプションが必要です。無料で作成できます。
- Azure ポータルで、新しい「Document Intelligence」サービス リソースを作成します。
- 作成したら、リソースの「キーとエンドポイント」セクションに移動し、キー 1 またはキー 2 とエンドポイントをコピーします。
- 開発環境:
- 適切な Microsoft Visual C++ 再頒布可能パッケージがインストールされたVisual Studio (2015、2017、2019、または 2022) 。
- 互換性のある .NET プラットフォーム (.NET Core、.NET 5+、.NET Standard 2.0 など) を対象とする C# プロジェクト。
- Microsoft.CognitiveServices.Speech NuGet パッケージをインストールします。NuGet パッケージ マネージャー コンソールからインストールできます。
Form1


Azure.AI.FormRecognizer を導入。

Form1.cs
using Azure;
using Azure.AI.FormRecognizer.DocumentAnalysis;
using PdfiumViewer;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Net.Mime.MediaTypeNames;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
namespace PdfToTextAz
{
public partial class Form1 : Form
{
//control clsResize 画面表示を拡大縮小します。
clsResize _form_resize;
//Form1オブジェクトを保持するためのフィールド
private static Form1 _form1Instance;
//
private static string endpoint = "your endpoint";
private static string apiKey = "your key";
private static string selectfile = "";
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
private static extern bool AllocConsole();
public Form1()
{
InitializeComponent();
//clsResize
_form_resize = new clsResize(this); //I put this after the initialize event to be sure that all controls are initialized properly
this.Load += new EventHandler(_Load); //This will be called after the initialization // form_load
this.Resize += new EventHandler(_Resize); //form_resize
//
AllocConsole();
string filePath = System.IO.Directory.GetCurrentDirectory() + @"\KeyText.txt";
if (File.Exists(filePath))
{
StreamReader sr = new StreamReader(filePath, Encoding.GetEncoding("Shift_JIS"));
int i = 0;
string linetext = "";
while (sr.Peek() != -1)
{
linetext=sr.ReadLine();
i += 1;
if (i == 1)
{
apiKey = linetext;
}else if (i == 2)
{
endpoint = linetext;
}
Console.WriteLine(linetext);
}
sr.Close();
}
else
{
//Console.WriteLine("ファイルが存在しません");
}
textBox2.Text = apiKey;
textBox3.Text = endpoint;
File.WriteAllText(System.IO.Directory.GetCurrentDirectory() + @"\Text.txt", "");
}
//clsResize _Load
private void _Load(object sender, EventArgs e)
{
_form_resize._get_initial_size();
}
//clsResize _Resize
private void _Resize(object sender, EventArgs e)
{
_form_resize._resize();
}
private void button2_Click(object sender, EventArgs e)
{
this.Close();
}
private void button3_Click(object sender, EventArgs e)
{
textBox1.Text = "";
}
private void button4_Click(object sender, EventArgs e)
{
//OpenFileDialogクラスのインスタンスを作成
OpenFileDialog ofd = new OpenFileDialog();
//はじめのファイル名を指定する
//はじめに「ファイル名」で表示される文字列を指定する
ofd.FileName = "default.pdf";
//はじめに表示されるフォルダを指定する
//指定しない(空の文字列)の時は、現在のディレクトリが表示される
ofd.InitialDirectory = System.Environment.CurrentDirectory + @"\";
//[ファイルの種類]に表示される選択肢を指定する
//指定しないとすべてのファイルが表示される
ofd.Filter = "PDFファイル(*.pdf)|*.pdf|JPEGファイル(*.jpg)|*.jpg|すべてのファイル(*.*)|*.*";
//[ファイルの種類]ではじめに選択されるものを指定する
//2番目の「すべてのファイル」が選択されているようにする
ofd.FilterIndex = 1;
//タイトルを設定する
ofd.Title = "開くファイルを選択してください";
//ダイアログボックスを閉じる前に現在のディレクトリを復元するようにする
ofd.RestoreDirectory = true;
//存在しないファイルの名前が指定されたとき警告を表示する
//デフォルトでTrueなので指定する必要はない
ofd.CheckFileExists = true;
//存在しないパスが指定されたとき警告を表示する
//デフォルトでTrueなので指定する必要はない
ofd.CheckPathExists = true;
//ダイアログを表示する
if (ofd.ShowDialog() == DialogResult.OK)
{
//OKボタンがクリックされたとき、選択されたファイル名を表示する
Console.WriteLine(ofd.FileName);
FileInfo file = new FileInfo(ofd.FileName);
long size = file.Length;
size = size / 1024 ; //KB
if (size >= 4000)
{
MessageBox.Show("ファイルサイズは、" + size + "KBです。選択不可です。", "ファイルサイズエラー");
}else if (size < 4000)
{
webView21.Source = new Uri(ofd.FileName);
textBox4.Text = ofd.FileName;
}
}
}
async static Task<string> ToText()
{
var client = new DocumentAnalysisClient(new Uri(endpoint), new AzureKeyCredential(apiKey));
var sb = new StringBuilder();
// F0の制限 2ページ 4MB以下
var fileStream = File.OpenRead(selectfile);
var stopRecognition = new TaskCompletionSource<int>();
// ローカルファイルまたは URL から解析
var operation = await client.AnalyzeDocumentAsync(WaitUntil.Completed, "prebuilt-read", fileStream);
var result = operation.Value;
foreach (var page in result.Pages)
{
foreach (var line in page.Lines)
{
Console.WriteLine(line.Content);
sb.Append(line.Content + "\n\r" + "\n\r");
File.AppendAllText(System.IO.Directory.GetCurrentDirectory() + @"\Text.txt", line.Content + "\n");
}
}
stopRecognition.TrySetResult(0);
return sb.ToString();
}
private async void button1_Click(object sender, EventArgs e)
{
apiKey = textBox2.Text;
endpoint = textBox3.Text;
selectfile = textBox4.Text;
button1.Enabled = false;
textBox1.Text = await ToText();
button1.Enabled = true;
}
}
}
clsResize.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
public class clsResize
{
List<System.Drawing.Rectangle> _arr_control_storage = new List<System.Drawing.Rectangle>();
private bool showRowHeader = false;
public clsResize(Form _form_)
{
form = _form_; //the calling form
_formSize = _form_.ClientSize; //Save initial form size
_fontsize = _form_.Font.Size; //Font size
//ADD
var _controls = _get_all_controls(form);//call the enumerator
FontTable = new Dictionary<string, float>();
ControlTable = new Dictionary<string, System.Drawing.Rectangle>();
foreach (Control control in _controls) //Loop through the controls
{
FontTable.Add(control.Name, control.Font.Size);
ControlTable.Add(control.Name, control.Bounds);
}
//ADD
}
//ADD
Dictionary<string, float> FontTable;
Dictionary<string, System.Drawing.Rectangle> ControlTable;
//ADD
private float _fontsize { get; set; }
private System.Drawing.SizeF _formSize { get; set; }
private Form form { get; set; }
public void _get_initial_size() //get initial size//
{
var _controls = _get_all_controls(form);//call the enumerator
foreach (Control control in _controls) //Loop through the controls
{
_arr_control_storage.Add(control.Bounds); //saves control bounds/dimension
//If you have datagridview
if (control.GetType() == typeof(DataGridView))
_dgv_Column_Adjust(((DataGridView)control), showRowHeader);
}
}
public void _resize() //Set the resize
{
double _form_ratio_width = (double)form.ClientSize.Width / (double)_formSize.Width; //ratio could be greater or less than 1
double _form_ratio_height = (double)form.ClientSize.Height / (double)_formSize.Height; // this one too
var _controls = _get_all_controls(form); //reenumerate the control collection
int _pos = -1;//do not change this value unless you know what you are doing
foreach (Control control in _controls)
{
//ADD
this._fontsize = FontTable[control.Name]; //<-取得したコントロールのフォントサイズ値で上書きするためにこれを追加
//ADD
// do some math calc
_pos += 1;//increment by 1;
System.Drawing.Size _controlSize = new System.Drawing.Size((int)(_arr_control_storage[_pos].Width * _form_ratio_width),
(int)(_arr_control_storage[_pos].Height * _form_ratio_height)); //use for sizing
System.Drawing.Point _controlposition = new System.Drawing.Point((int)
(_arr_control_storage[_pos].X * _form_ratio_width), (int)(_arr_control_storage[_pos].Y * _form_ratio_height));//use for location
//set bounds
control.Bounds = new System.Drawing.Rectangle(_controlposition, _controlSize); //Put together
//Assuming you have a datagridview inside a form()
//if you want to show the row header, replace the false statement of
//showRowHeader on top/public declaration to true;
if (control.GetType() == typeof(DataGridView))
_dgv_Column_Adjust(((DataGridView)control), showRowHeader);
//Font AutoSize
control.Font = new System.Drawing.Font(form.Font.FontFamily,
(float)(((Convert.ToDouble(_fontsize) * _form_ratio_width) / 2) +
((Convert.ToDouble(_fontsize) * _form_ratio_height) / 2)));
}
}
private void _dgv_Column_Adjust(DataGridView dgv, bool _showRowHeader) //if you have Datagridview
//and want to resize the column base on its dimension.
{
int intRowHeader = 0;
const int Hscrollbarwidth = 5;
if (_showRowHeader)
intRowHeader = dgv.RowHeadersWidth;
else
dgv.RowHeadersVisible = false;
for (int i = 0; i < dgv.ColumnCount; i++)
{
if (dgv.Dock == DockStyle.Fill) //in case the datagridview is docked
dgv.Columns[i].Width = ((dgv.Width - intRowHeader) / dgv.ColumnCount);
else
dgv.Columns[i].Width = ((dgv.Width - intRowHeader - Hscrollbarwidth) / dgv.ColumnCount);
}
}
private static IEnumerable<Control> _get_all_controls(Control c)
{
return c.Controls.Cast<Control>().SelectMany(item =>
_get_all_controls(item)).Concat(c.Controls.Cast<Control>()).Where(control =>
control.Name != string.Empty);
}
}