🗺️

TIF画像の縮尺を変えずに、PDFへ変換するスクリプトを作った

2025/03/01に公開

1. はじめに

地積測量図や建築図面などの精密な図面は、多くの場合TIF形式で保存されています。これらの図面は高い精度が要求される重要な資料ですが、クライアントへの提出や電子申請ではPDF形式が必要になることが多いです。

しかし、市販の画像変換ソフトや無料のオンラインコンバーターでTIF画像をPDFに変換すると、多くの場合、以下のような問題が発生します。

  • 画像の解像度(DPI)が変わってしまい、縮尺が不正確になる
  • 用紙サイズに合わせた適切な配置ができない
  • 変換後の画質が劣化する
  • 一括処理が難しい

特に土地家屋調査士業務において、地積測量図の精度は非常に重要です。1mmの誤差が実際の土地では数cm~数十cmの誤差につながる可能性があります。

この記事で紹介するPowerShellスクリプトは、これらの問題を解決し、以下の特徴を持っています:

  • 元画像の解像度(DPI)を維持して正確な縮尺を保持
  • A3やA4など標準用紙サイズに適切に配置
  • 高品質な出力で図面の細部まで鮮明に再現
  • フォルダ内の複数TIFファイルを一括変換可能

専門的な知識がなくても、このスクリプトを使うことで、誰でも簡単に高精度なPDF変換が可能になります。

2. 画像とPDF変換の基礎知識

2.1 DPIとは何か

DPI(Dots Per Inch)とは、1インチ(約2.54cm)あたりのドット(点)の数を表す単位です。簡単に言えば、画像の「きめの細かさ」を示す数値です。

DPIが高いほど、より多くの情報が詰め込まれているため、画像は精細になります:

  • 72DPI:Webサイト表示用(一般的なモニター表示)
  • 300DPI:一般的な印刷物(チラシやパンフレット)
  • 400-600DPI:高品質な印刷(写真集や美術書)
  • 600-1200DPI以上:精密図面(地積測量図、設計図面)

地積測量図などの測量図面では、実寸に対する正確性が非常に重要です。例えば、縮尺1/500の図面では、図面上の1mmが実際の土地では50cmに相当します。そのため、測量図面を変換する際には、この精度を保つためにDPIを正確に維持する必要があります。

DPIが変わると何が起こるのでしょうか?例えば、元の画像が600DPIで作成されていたものが300DPIに変換されると、同じ用紙に印刷した場合、図面は2倍の大きさになってしまいます。これにより、縮尺が崩れ、実際の寸法と一致しなくなります。

2.2 TIFとPDFの違い

TIF(Tagged Image File Format)の特徴:

  • 非圧縮または可逆圧縮で保存できるため、画質劣化がない
  • レイヤー対応や高ビット深度をサポート
  • 解像度(DPI)情報を正確に保持
  • CADや測量ソフトなど専門ソフトで広く使用される
  • ファイルサイズが大きい

PDF(Portable Document Format)の特徴:

  • 異なるOS間でも同じ見た目を保持できる
  • 複数ページを1つのファイルに収められる
  • 電子署名や注釈などの機能を持つ
  • 多くの電子申請システムで採用されている
  • 印刷や共有が容易

土地家屋調査士業務においては、精密な作図・編集作業にはTIF形式が適しています。また、法務局への電子申請はTIF形式で行われています。一方で、依頼人への納品や他の関係機関への提出ではPDF形式が求められることも多いため、両形式間の正確な変換技術は実務上重要となります。

3. PowerShellと変換スクリプトの機能紹介

3.1 PowerShellとは

PowerShellは、Microsoftが開発したコマンドラインシェルおよびスクリプト言語です。Windows OSに標準搭載されており、システム管理やファイル操作などの自動化に使われます。簡単に言えば、コンピュータに自動的に作業をさせるための指示書を書くツールです。

PowerShellの基本的な特徴:

  • Windows 7以降のすべてのWindowsに標準搭載
  • 青い背景の「PowerShell」アプリからアクセス可能
  • コマンドを入力して実行するか、スクリプトファイル(.ps1)を作成して一連の処理を自動化できる
  • 通常のソフトウェアではできないような、細かい操作や自動処理が可能

スクリプトとは:
スクリプトとは、コンピュータが実行する一連の命令をテキストファイルに記述したものです。例えるなら、料理のレシピのようなもので、コンピュータがその手順に従って処理を行います。

PowerShellスクリプト(.ps1ファイル)を実行するには、通常、右クリックして「PowerShellで実行」を選択するか、PowerShellウィンドウで直接実行することができます。

3.2 変換スクリプトの機能

このTIF変換用PowerShellスクリプトには、以下のような機能があります:

主な特徴:

  • 元画像のDPIを正確に維持した変換(縮尺保持)
  • A3、A4などの標準用紙サイズに対応
  • 図面を用紙中央に適切に配置
  • 縮小率を調整可能(余白確保のため)
  • フォルダ内の複数TIFファイルを一括変換
  • 高品質モードでの変換による鮮明な出力

対応ファイル形式:

  • TIF、TIFF形式の画像ファイル
  • 様々な解像度(DPI)に対応
  • カラー、グレースケール、白黒すべてに対応

動作環境:

  • Windows 10/11
  • PowerShell 5.1以上
  • Microsoft Print to PDF(Windows 10以降は標準搭載)または他のPDFプリンター

このスクリプトの最大の利点は、市販のソフトでは難しい「DPIを維持した正確な変換」を実現している点です。特に図面の寸法精度が重要な測量業務において、このスクリプトは非常に価値のあるツールとなります。

3.3 変換スクリプト

長いので末尾に。

4. 使い方ガイド

4.1 スクリプトのダウンロードと準備

  1. 末尾にあるスクリプトをコピーし、「TifToPdf.ps1」という名前で保存します。
  2. 変換したいTIFファイルがあるフォルダに、このスクリプトファイルを配置します。

初めてPowerShellスクリプトを使用する方のために、以下に基本的な実行手順を図解します:

  1. PowerShellの起動方法:

    • Windowsのスタートメニューで「PowerShell」と入力
    • 表示された「Windows PowerShell」アプリをクリック
  2. スクリプトの実行方法(コマンドラインから):

    • PowerShellウィンドウが開いたら、スクリプトがあるフォルダに移動するコマンドを入力:
      cd C:\変換したいファイルがあるフォルダのパス
      
    • スクリプトを実行するコマンドを入力:
      .\TifToPdf.ps1
      

注意事項:

  • 初回実行時にセキュリティ警告が表示される場合があります。その場合は、以下のコマンドを実行してから再度スクリプトを実行してください:
    Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Bypass
    
  • PDFプリンターがインストールされていることを確認してください(Windows 10/11なら「Microsoft Print to PDF」が標準搭載されています)。

4.2 基本的な使い方

スクリプトを実行すると、以下のような選択肢が表示されます:

====================================================
      TIF to PDF 変換ツール (最終修正版)
====================================================
A3サイズ: 420mm × 297mm
A4サイズ: 297mm × 210mm

変換モードを選択してください:
  1: 元画像のDPIを維持(設計図の精密変換)
  2: 標準変換
  3: 詳細モード(ログ詳細表示)
  4: カスタム縮小率を指定
  5: 用紙サイズを選択
選択 [1]:

最も推奨されるのは「1: 元画像のDPIを維持」モードです。特に地積測量図など、寸法精度が重要な図面にはこのモードを選択してください。

選択後、縮小率を指定する画面が表示されます:

縮小率を入力(精密変換には0.98-1.0を推奨)[0.99]:

1.0と指定することをお勧めします。

設定が完了すると変換が開始され、同じフォルダ内に「PDF」というサブフォルダが作成され、そこに変換されたPDFファイルが保存されます。

4.3 応用設定

用紙サイズの選択(モード5)

用紙サイズを変更したい場合は、モード5を選択します:

用紙サイズを選択してください:
  1: A3 (420mm × 297mm)
  2: A4 (297mm × 210mm)
選択 [1]:

地積測量図は通常A3サイズであることが多いため、特に理由がなければA3を選択するとよいでしょう。

縮小率の調整(モード4)

図面の配置を微調整したい場合は、モード4を選択して縮小率を指定できます:

  • 0.9(90%):用紙に対して小さめに配置される
  • 0.95(95%):わずかに小さめ
  • 0.98-0.99(98-99%):ほぼ原寸大だが、わずかな余白あり
  • 1.0(100%):完全な原寸大(余白がほとんどなくなる場合あり)

詳細モード(モード3)

変換に問題がある場合や、プロセスの詳細を確認したい場合は、モード3を選択します。このモードでは、以下のような詳細情報が表示されます:

  • 元画像の解像度
  • 元画像の実寸サイズ
  • 出力DPI
  • キャンバスサイズや描画位置
  • エラーの詳細情報(問題が発生した場合)

5. 技術解説

5.1 変換の仕組み

このスクリプトの変換プロセスは以下のような流れで進行します:

  1. 入力TIFファイルの読み込み:System.Drawing.Imageを使用して画像を読み込みます
  2. 解像度(DPI)情報の取得:元画像のHorizontalResolutionとVerticalResolutionプロパティから取得
  3. 用紙サイズの計算:選択された用紙サイズ(A3/A4など)をピクセル単位に変換
  4. スケーリング計算:元画像を用紙に適切に配置するためのスケール比を計算
  5. 高解像度キャンバスの作成:元のDPIを維持した新しいキャンバスに画像を描画
  6. PDF出力:Microsoft Print to PDFを使用してPDF形式に出力

特に重要なのは、元画像のDPI情報を維持したまま新しいキャンバスを作成する処理です。これにより、変換後も縮尺の正確性が保たれます。

また、アスペクト比(縦横比)を維持したまま最適な大きさに調整し、用紙の中央に配置する処理も、図面の見やすさを確保するために重要な役割を果たしています。

5.2 コード解説(初心者向け)

スクリプト内の主要な関数とその役割を簡単に説明します:

  1. Convert-TifToPdf関数

    • 1つのTIFファイルをPDFに変換する中心的な機能
    • 引数:入力ファイル、出力ファイル、縮小率など
    • 戻り値:変換の成功/失敗
  2. Process-TifFiles関数

    • フォルダ内のTIFファイルを一括処理する機能
    • 進捗バーの表示や結果の集計を行う
  3. Get-SafePath関数

    • ファイル名に使えない文字を安全に置換する機能
    • ファイル操作時のエラーを防止する

主要なパラメータとその意味:

  • $ScaleFactor:図面の縮小率(0.98 = 98%)
  • $PreserveDpi:元画像のDPIを維持するかのフラグ
  • $PaperSize:出力用紙サイズ("A3"、"A4"など)
  • $Verbose:詳細ログを表示するかのフラグ

技術的な知識がなくても調整できる重要なポイントは以下の通りです:

  • 用紙サイズの選択(A3/A4)
  • 縮小率の調整(0.9~1.0)
  • DPI維持モードの選択(精密変換に重要)

これらのパラメータは、スクリプト実行時のメニューから簡単に設定できるため、プログラミングの知識がなくても適切な調整が可能です。

6. 実践例と効果

業務効率化への貢献

このスクリプトを導入することで、以下のような業務効率化が期待できます:

  • 時間短縮:手動での変換作業が不要になり、一括処理が可能
  • 精度向上:人為的なミスや設定忘れによる精度低下を防止
  • コスト削減:有料の変換ソフトが不要になる
  • 品質向上:常に高品質で一貫した変換結果が得られる

実際、100枚の地積測量図のTIFファイルをPDFに変換する作業が、手動では1日かかっていたものが、このスクリプトでは15分程度で完了するようになりました。

7. よくある質問とトラブルシューティング

Q: 「実行ポリシーによって...スクリプトの実行が無効になっています」というエラーが表示される

A: これはWindowsのセキュリティ設定によるものです。一時的に実行ポリシーを変更するには、PowerShellを管理者として実行し、以下のコマンドを入力してください:

Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Bypass

実行後、スクリプトを再度実行してみてください。

Q: PowerShellウィンドウが一瞬で閉じてしまい、スクリプトが実行されない

A: スクリプトファイルを直接ダブルクリックすると、このような問題が発生することがあります。代わりに、右クリックして「PowerShellで実行」を選択するか、PowerShellウィンドウを先に開いてからスクリプトを実行してください。

Q: PDFが生成されない、または「PDFプリンターが見つかりません」というエラーが表示される

A: Windows 10/11に標準搭載されている「Microsoft Print to PDF」が正しく設定されているか確認してください。コントロールパネル→デバイスとプリンター で確認できます。見つからない場合は、Windows機能の追加から「Microsoft Print to PDF」を有効にしてください。

Q: 変換されたPDFの画質が粗い

A: 以下を確認してください:

  • モード1(元画像のDPIを維持)を選択しているか
  • 元のTIF画像自体の解像度が十分に高いか
  • 詳細モード(モード3)で、実際にどのDPI値が使用されているか確認する

Q: 図面が用紙サイズに対して小さすぎる/大きすぎる

A: 縮小率を調整してみてください:

  • 小さすぎる場合:縮小率を大きくする(例:0.9→0.95→0.98)
  • 大きすぎる場合:縮小率を小さくする(例:0.99→0.95→0.9)

Q: 変換に時間がかかる

A: 高解像度のTIF画像を処理する場合、特にPCのスペックによっては時間がかかる場合があります。処理中はPCに負荷がかからないよう、他の重い処理は避けることをお勧めします。

Q: 用紙の向き(縦/横)が正しくない

A: このスクリプトは自動的に横向き(ランドスケープ)モードで出力します。これは地積測量図が横長であることが多いためです。

8. 発展的な使い方

バッチ処理での応用

複数のフォルダを処理したい場合、以下のようなバッチファイル(.bat)を作成すると便利です:

@echo off
echo TIF一括変換処理を開始します
cd /d C:\測量図フォルダ1
powershell -ExecutionPolicy Bypass -File TifToPdf.ps1
cd /d C:\測量図フォルダ2
powershell -ExecutionPolicy Bypass -File TifToPdf.ps1
echo 処理が完了しました
pause

スクリプトのカスタマイズ例

プログラミングの知識がなくても、以下のような簡単なカスタマイズが可能です:

  1. 用紙サイズの追加
    スクリプト冒頭の$PAPER_SIZESに新しいサイズを追加することで、カスタムサイズを定義できます。

    "B4" = @{
        "Width" = 353
        "Height" = 250
        "Kind" = [System.Drawing.Printing.PaperKind]::B4
    }
    
  2. 出力フォルダの変更
    Process-TifFiles関数内の$pdfFolderの定義を変更することで、出力先を変更できます。

他のツールとの連携アイデア

  • クラウドストレージとの連携:OneDriveやGoogleドライブの同期フォルダで使用
  • 測量CADとの連携:CADソフトの出力フォルダを監視して自動変換
  • ファイル名の一括リネーム:変換前にファイル名を整理するスクリプトと組み合わせる

9. まとめ

このPowerShellスクリプトは、特に土地家屋調査士業務において重要な、TIF形式の地積測量図をPDFに正確に変換するための実用的なツールです。

主なメリット:

  • 元画像のDPIを維持するため、縮尺が正確に保持される
  • 用紙サイズに最適化された配置が自動的に行われる
  • 一括処理により業務効率が大幅に向上する
  • 無料で利用できるWindows標準機能だけで実現できる

実務での活用シーン:

  • 顧客への電子データ納品用PDF作成
  • 他機関や関係者への提出資料作成
  • 社内での図面データ管理
  • 紙図面のスキャンデータを様々な形式で活用する場合

本記事で紹介したスクリプトは、測量図面を扱う業務において、精度を保ちながら効率化するための強力なツールとなるでしょう。プログラミングの専門知識がなくても、このスクリプトを活用することで、正確で高品質なPDF変換が可能になります。

今後も、皆様のフィードバックをもとに機能改善などを行う予定です。ぜひ実務でお試しいただき、ご意見やご感想をお寄せください。

10. スクリプト

# TIF to PDF変換スクリプト (最終修正版)
# 指定のフォルダ内のTIFファイルをPDFに変換します

# 必要なアセンブリの読み込み
Add-Type -AssemblyName System.Drawing
Add-Type -AssemblyName System.Windows.Forms

# 用紙サイズの定義(ミリメートル)
$PAPER_SIZES = @{
 "A3" = @{
     "Width" = 420
     "Height" = 297
     "Kind" = [System.Drawing.Printing.PaperKind]::A3
 }
 "A4" = @{
     "Width" = 297
     "Height" = 210
     "Kind" = [System.Drawing.Printing.PaperKind]::A4
 }
}

# 標準解像度(DPI)
$SCREEN_DPI = 96        # Windowsの標準DPI
$DEFAULT_PDF_DPI = 400  # PDF出力用DPI

# 安全なパスを生成する関数
function Get-SafePath {
 param (
     [string]$BasePath,
     [string]$FileName
 )
 
 # 無効な文字を置換
 $safeFileName = [System.IO.Path]::GetFileName($FileName) -replace '[\\/:*?"<>|]', '_'
 return Join-Path -Path $BasePath -ChildPath $safeFileName
}

# TIFファイルをPDFに変換する関数
function Convert-TifToPdf {
 param (
     [string]$InputFile,
     [string]$OutputFile,
     [double]$ScaleFactor = 0.98,
     [switch]$Verbose,
     [switch]$PreserveDpi,
     [string]$PaperSize = "A3"
 )

 # リソース追跡用配列
 $resources = @()

 if ($Verbose) {
     Write-Host "処理開始: $InputFile -> $OutputFile" -ForegroundColor Cyan
 } else {
     Write-Host "処理中: $([System.IO.Path]::GetFileName($InputFile))" -NoNewline
 }

 try {
     # 入力ファイルの存在確認
     if (-not (Test-Path -Path $InputFile -PathType Leaf)) {
         Write-Host " -> エラー: 入力ファイルが見つかりません" -ForegroundColor Red
         return $false
     }
     
     # 用紙サイズ情報の取得
     $paperSizeInfo = $PAPER_SIZES[$PaperSize]
     if ($null -eq $paperSizeInfo) {
         Write-Host " -> エラー: 指定された用紙サイズ '$PaperSize' は未定義です" -ForegroundColor Red
         return $false
     }
     
     $paperWidthMM = $paperSizeInfo.Width
     $paperHeightMM = $paperSizeInfo.Height
     $paperKind = $paperSizeInfo.Kind
     
     # 元の画像を読み込む
     $originalImage = [System.Drawing.Image]::FromFile($InputFile)
     $resources += $originalImage
     
     # 画像解像度の取得と処理
     $imageDpiX = $originalImage.HorizontalResolution
     $imageDpiY = $originalImage.VerticalResolution
     
     # 画像解像度が異常に低い場合は補正
     if ($imageDpiX -lt 72) { $imageDpiX = $DEFAULT_PDF_DPI }
     if ($imageDpiY -lt 72) { $imageDpiY = $DEFAULT_PDF_DPI }
     
     # 元画像のDPIに合わせてPDF出力DPI調整
     $outputDpi = if ($PreserveDpi) { $imageDpiX } else { $DEFAULT_PDF_DPI }
     
     # 画像情報(デバッグ用)
     if ($Verbose) {
         Write-Host "元画像: $($originalImage.Width)x$($originalImage.Height)px, ${imageDpiX}x${imageDpiY}dpi" -ForegroundColor Gray
         Write-Host "元画像実寸: $([Math]::Round(($originalImage.Width / $imageDpiX) * 25.4, 1))mm x $([Math]::Round(($originalImage.Height / $imageDpiY) * 25.4, 1))mm" -ForegroundColor Gray
         Write-Host "出力DPI: ${outputDpi}dpi" -ForegroundColor Gray
     }
     
     # 用紙サイズをピクセルに変換
     $paperWidthPixels = [int](($paperWidthMM / 25.4) * $SCREEN_DPI)
     $paperHeightPixels = [int](($paperHeightMM / 25.4) * $SCREEN_DPI)
     
     # 印刷用の用紙サイズ(出力DPIベース)
     $printWidthPixels = [int](($paperWidthMM / 25.4) * $outputDpi)
     $printHeightPixels = [int](($paperHeightMM / 25.4) * $outputDpi)
     
     # 印刷用の高解像度キャンバスを作成
     $canvas = New-Object System.Drawing.Bitmap $printWidthPixels, $printHeightPixels
     $resources += $canvas
     $canvas.SetResolution($outputDpi, $outputDpi)
     
     # グラフィックスオブジェクトを作成
     $graphics = [System.Drawing.Graphics]::FromImage($canvas)
     $resources += $graphics
     $graphics.Clear([System.Drawing.Color]::White)
     
     # 高品質設定
     $graphics.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic
     $graphics.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::HighQuality
     $graphics.PixelOffsetMode = [System.Drawing.Drawing2D.PixelOffsetMode]::HighQuality
     
     # 原寸維持でスケーリング計算
     $originalWidthMM = ($originalImage.Width / $imageDpiX) * 25.4
     $originalHeightMM = ($originalImage.Height / $imageDpiY) * 25.4
     
     # スケール比を計算
     $scaleX = ($paperWidthMM / $originalWidthMM) * $ScaleFactor
     $scaleY = ($paperHeightMM / $originalHeightMM) * $ScaleFactor
     $scale = [Math]::Min($scaleX, $scaleY)  # アスペクト比維持
     
     # 出力DPIでの描画サイズを計算
     $drawWidth = [int]($originalImage.Width * ($scale * $outputDpi / $imageDpiX))
     $drawHeight = [int]($originalImage.Height * ($scale * $outputDpi / $imageDpiY))
     
     # 中央配置の座標を計算
     $x = [int](($printWidthPixels - $drawWidth) / 2)
     $y = [int](($printHeightPixels - $drawHeight) / 2)
     
     if ($Verbose) {
         Write-Host "キャンバス: ${printWidthPixels}x${printHeightPixels}px @ ${outputDpi}dpi" -ForegroundColor Gray
         Write-Host "描画: (${x},${y}) サイズ: ${drawWidth}x${drawHeight}px スケール: $([Math]::Round($scale, 3))" -ForegroundColor Gray
     }
     
     # 描画
     $destRect = New-Object System.Drawing.Rectangle $x, $y, $drawWidth, $drawHeight
     $srcRect = New-Object System.Drawing.Rectangle 0, 0, $originalImage.Width, $originalImage.Height
     $graphics.DrawImage($originalImage, $destRect, $srcRect, [System.Drawing.GraphicsUnit]::Pixel)
     
     # 一時ファイルを準備
     $tempDir = Join-Path $env:TEMP ([Guid]::NewGuid().ToString())
     New-Item -ItemType Directory -Path $tempDir -Force | Out-Null
     $tempFile = Join-Path $tempDir "temp_image.png"
     
     # 高品質で保存
     $encoderParams = New-Object System.Drawing.Imaging.EncoderParameters(1)
     $qualityParam = New-Object System.Drawing.Imaging.EncoderParameter([System.Drawing.Imaging.Encoder]::Quality, 100)
     $encoderParams.Param[0] = $qualityParam
     $pngCodecInfo = [System.Drawing.Imaging.ImageCodecInfo]::GetImageEncoders() | Where-Object { $_.MimeType -eq 'image/png' }
     
     # キャンバスを保存
     $canvas.Save($tempFile, $pngCodecInfo, $encoderParams)
     
     if ($Verbose) {
         Write-Host "一時ファイル作成: $tempFile" -ForegroundColor Gray
     }
     
     # リソース解放
     foreach ($res in $resources) {
         if ($null -ne $res -and $res -is [System.IDisposable]) {
             $res.Dispose()
         }
     }
     # リソース追跡配列をクリア
     $resources = @()
     
     # 一時ファイルからPDF生成
     $tempImage = [System.Drawing.Image]::FromFile($tempFile)
     $resources += $tempImage
     
     # PDFプリンターの検証
     $pdfPrinterExists = $false
     $preferredPdfPrinters = @(
         "Microsoft Print to PDF",
         "Microsoft XPS Document Writer",
         "Adobe PDF",
         "Foxit PDF Printer"
     )
     
     $printers = [System.Drawing.Printing.PrinterSettings]::InstalledPrinters
     $selectedPrinter = $null
     
     foreach ($printerName in $preferredPdfPrinters) {
         foreach ($installedPrinter in $printers) {
             if ($installedPrinter -eq $printerName) {
                 $selectedPrinter = $printerName
                 $pdfPrinterExists = $true
                 break
             }
         }
         if ($pdfPrinterExists) { break }
     }
     
     if (-not $pdfPrinterExists) {
         Write-Host " -> エラー: PDFプリンターが見つかりません。Microsoft Print to PDFまたは互換プリンターをインストールしてください" -ForegroundColor Red
         return $false
     }
     
     # プリントドキュメント作成
     $printDoc = New-Object System.Drawing.Printing.PrintDocument
     $resources += $printDoc
     $printDoc.DocumentName = [System.IO.Path]::GetFileNameWithoutExtension($InputFile)
     $printDoc.PrinterSettings.PrinterName = $selectedPrinter
     $printDoc.PrinterSettings.PrintToFile = $true
     $printDoc.PrinterSettings.PrintFileName = $OutputFile
     
     # 用紙サイズ設定
     $paperSizeFound = $false
     foreach ($predefinedPaperSize in $printDoc.PrinterSettings.PaperSizes) {
         if ($predefinedPaperSize.Kind -eq $paperKind) {
             $printDoc.DefaultPageSettings.PaperSize = $predefinedPaperSize
             $paperSizeFound = $true
             if ($Verbose) {
                 Write-Host "プリンターの${PaperSize}定義を使用: $($predefinedPaperSize.Width) x $($predefinedPaperSize.Height)" -ForegroundColor Gray
             }
             break
         }
     }
     
     # 定義済み用紙が見つからない場合、カスタムサイズで作成
     if (-not $paperSizeFound) {
         $customPaperSize = New-Object System.Drawing.Printing.PaperSize($PaperSize, $paperWidthPixels, $paperHeightPixels)
         $printDoc.DefaultPageSettings.PaperSize = $customPaperSize
         if ($Verbose) {
             Write-Host "カスタム${PaperSize}定義を作成: $($customPaperSize.Width) x $($customPaperSize.Height)" -ForegroundColor Gray
         }
     }
     
     # 横長設定
     $printDoc.DefaultPageSettings.Landscape = $true
     
     # 余白をゼロに設定
     $printDoc.DefaultPageSettings.Margins = New-Object System.Drawing.Printing.Margins(0, 0, 0, 0)
     
     # 印刷コントローラの設定(ダイアログ非表示)
     $printDoc.PrintController = New-Object System.Drawing.Printing.StandardPrintController
     
     # プリントイベントハンドラ
     $printDoc.add_PrintPage({
         param($sender, $e)
         
         # 高品質設定
         $e.Graphics.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic
         $e.Graphics.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::HighQuality
         $e.Graphics.PixelOffsetMode = [System.Drawing.Drawing2D.PixelOffsetMode]::HighQuality
         
         # 用紙の描画可能領域を取得
         $printableWidth = $e.MarginBounds.Width
         $printableHeight = $e.MarginBounds.Height
         
         # 画像の実際のサイズ比を維持してフィットさせる
         $imageRatio = [double]$tempImage.Width / [double]$tempImage.Height
         $pageRatio = [double]$printableWidth / [double]$printableHeight
         
         $drawWidth = $printableWidth
         $drawHeight = $printableHeight
         
         # アスペクト比の調整
         if ($imageRatio -gt $pageRatio) {
             # 画像が用紙より横長の場合
             $drawHeight = $printableWidth / $imageRatio
             $y = ($printableHeight - $drawHeight) / 2
             $x = 0
         } else {
             # 画像が用紙より縦長の場合
             $drawWidth = $printableHeight * $imageRatio
             $x = ($printableWidth - $drawWidth) / 2
             $y = 0
         }
         
         # 描画位置を調整(余白の位置から開始)
         $x += $e.MarginBounds.Left
         $y += $e.MarginBounds.Top
         
         # 画像全体を描画(フィットさせる)
         $destRect = New-Object System.Drawing.RectangleF($x, $y, $drawWidth, $drawHeight)
         $e.Graphics.DrawImage($tempImage, $destRect)
         
         # 印刷終了
         $e.HasMorePages = $false
     })
     
     # 印刷実行
     try {
         $printDoc.Print()
         if ($Verbose) {
             Write-Host "PDF生成中..." -ForegroundColor Gray
         }
     }
     catch {
         Write-Host " -> PDF生成エラー: $_" -ForegroundColor Red
         return $false
     }
     finally {
         # リソース解放は必ず実行
         foreach ($res in $resources) {
             if ($null -ne $res -and $res -is [System.IDisposable]) {
                 $res.Dispose()
             }
         }
     }
     
     # 一時ファイル削除を試みる
     try {
         Start-Sleep -Seconds 1  # 印刷処理完了を待機
         if (Test-Path -Path $tempFile) {
             Remove-Item -Path $tempFile -Force -ErrorAction SilentlyContinue
         }
         if (Test-Path -Path $tempDir) {
             Remove-Item -Path $tempDir -Force -Recurse -ErrorAction SilentlyContinue
         }
     }
     catch {
         if ($Verbose) {
             Write-Host "一時ファイル削除中にエラー発生: $_" -ForegroundColor Yellow
         }
     }
     
     # 結果確認
     if (Test-Path $OutputFile) {
         if ($Verbose) {
             Write-Host "変換成功: $OutputFile" -ForegroundColor Green
             
             # ファイルサイズを取得
             $fileInfo = Get-Item $OutputFile
             Write-Host "ファイルサイズ: $([Math]::Round($fileInfo.Length / 1KB, 2))KB" -ForegroundColor Gray
         } else {
             Write-Host " -> 成功" -ForegroundColor Green
         }
         return $true
     } else {
         Write-Host " -> 失敗: PDFが生成されませんでした" -ForegroundColor Red
         return $false
     }
 }
 catch {
     Write-Host " -> エラー: $_" -ForegroundColor Red
     return $false
 }
 finally {
     # リソース解放は必ず実行
     foreach ($res in $resources) {
         if ($null -ne $res -and $res -is [System.IDisposable]) {
             try {
                 $res.Dispose()
             }
             catch {
                 # 解放エラーは無視
             }
         }
     }
 }
}

# メイン処理関数
function Process-TifFiles {
 param (
     [string]$SourceFolder,
     [string]$OutputFolder,
     [double]$ScaleFactor = 0.98,
     [switch]$Verbose,
     [switch]$PreserveDpi,
     [string]$PaperSize = "A3"
 )
 
 # パスの絶対パス化と検証
 $SourceFolder = [System.IO.Path]::GetFullPath($SourceFolder)
 $OutputFolder = [System.IO.Path]::GetFullPath($OutputFolder)
 
 # フォルダ存在確認
 if (-not (Test-Path -Path $SourceFolder -PathType Container)) {
     Write-Host "エラー: 指定された入力フォルダが存在しません: $SourceFolder" -ForegroundColor Red
     return
 }
 
 # フォルダ作成(存在しない場合)
 if (-not (Test-Path -Path $OutputFolder)) {
     try {
         New-Item -ItemType Directory -Path $OutputFolder -Force | Out-Null
         Write-Host "出力フォルダを作成しました: $OutputFolder" -ForegroundColor Yellow
     }
     catch {
         Write-Host "エラー: 出力フォルダを作成できません: $_" -ForegroundColor Red
         return
     }
 }
 
 # TIFファイルを検索(大文字小文字を区別しない)
 $tifFiles = @()
 $tifExtensions = @("*.tif", "*.tiff")
 
 foreach ($ext in $tifExtensions) {
     $tifFiles += Get-ChildItem -Path $SourceFolder -Filter $ext -File
 }
 
 # 重複を排除(大文字小文字が異なる場合もファイル名で一意に)
 $uniqueFiles = @{}
 foreach ($file in $tifFiles) {
     $uniqueFiles[$file.FullName] = $file
 }
 $tifFiles = $uniqueFiles.Values
 
 # デバッグ情報を表示
 Write-Host "検索場所: $SourceFolder" -ForegroundColor Gray
 Write-Host "*.tif/*.tiff ファイル: $($tifFiles.Count)個" -ForegroundColor Gray
 
 # ファイル数確認
 if ($tifFiles.Count -eq 0) {
     Write-Host "変換対象のTIFファイルが見つかりません。" -ForegroundColor Yellow
     return
 }
 
 Write-Host "合計 $($tifFiles.Count) 個のファイルを変換します" -ForegroundColor Cyan
 
 # プログレスバー初期化
 $progressCount = 0
 
 # 各ファイルを処理
 $successCount = 0
 foreach ($file in $tifFiles) {
     # プログレスバー更新
     $progressCount++
     $progressPercentage = [int](($progressCount / $tifFiles.Count) * 100)
     Write-Progress -Activity "TIF to PDF変換" -Status "$progressCount / $($tifFiles.Count)" -PercentComplete $progressPercentage
     
     # 出力ファイル名(安全なパスを生成)
     $outputFile = Get-SafePath -BasePath $OutputFolder -FileName "$([System.IO.Path]::GetFileNameWithoutExtension($file.Name)).pdf"
     
     # 変換実行
     $result = Convert-TifToPdf -InputFile $file.FullName -OutputFile $outputFile -ScaleFactor $ScaleFactor -Verbose:$Verbose -PreserveDpi:$PreserveDpi -PaperSize $PaperSize
     
     if ($result) {
         $successCount++
     }
 }
 
 # プログレスバー完了
 Write-Progress -Activity "TIF to PDF変換" -Completed
 
 # 結果報告
 Write-Host "変換完了: $successCount / $($tifFiles.Count) ファイルが正常に変換されました" -ForegroundColor Green
}

# スクリプト実行
function Start-Conversion {
 # タイトル表示
 Write-Host "====================================================" -ForegroundColor Cyan
 Write-Host "      TIF to PDF 変換ツール (最終修正版)" -ForegroundColor Cyan
 Write-Host "====================================================" -ForegroundColor Cyan
 
 # 用紙サイズ情報表示
 foreach ($size in $PAPER_SIZES.Keys) {
     Write-Host "${size}サイズ: $($PAPER_SIZES[$size].Width)mm × $($PAPER_SIZES[$size].Height)mm" -ForegroundColor Cyan
 }
 Write-Host ""
 
 # カレントディレクトリを取得
 $currentDir = Get-Location
 
 # PDFフォルダを準備
 $pdfFolder = Join-Path -Path $currentDir -ChildPath "PDF"
 
 # オプション選択
 Write-Host "変換モードを選択してください:" -ForegroundColor Yellow
 Write-Host "  1: 元画像のDPIを維持(設計図の精密変換)" -ForegroundColor Green
 Write-Host "  2: 標準変換" -ForegroundColor White
 Write-Host "  3: 詳細モード(ログ詳細表示)" -ForegroundColor White
 Write-Host "  4: カスタム縮小率を指定" -ForegroundColor White
 Write-Host "  5: 用紙サイズを選択" -ForegroundColor White
 $option = Read-Host "選択 [1]"
 
 # デフォルト選択
 if ([string]::IsNullOrWhiteSpace($option)) {
     $option = "1"
 }
 
 # 用紙サイズ選択(デフォルトはA3)
 $selectedPaperSize = "A3"
 
 # 選択に応じた処理
 switch ($option) {
     "2" {
         # 標準モード
         Process-TifFiles -SourceFolder $currentDir -OutputFolder $pdfFolder -PaperSize $selectedPaperSize
     }
     "3" {
         # 詳細モード
         Process-TifFiles -SourceFolder $currentDir -OutputFolder $pdfFolder -Verbose -PaperSize $selectedPaperSize
     }
     "4" {
         # カスタム縮小率
         $scaleInput = Read-Host "縮小率を入力(0.9 = 90%, 0.8 = 80%)[0.98]"
         if ([string]::IsNullOrWhiteSpace($scaleInput)) {
             $scaleFactor = 0.98
         } else {
             try {
                 $scaleFactor = [double]$scaleInput
                 if ($scaleFactor -le 0 -or $scaleFactor -gt 1) {
                     Write-Host "警告: 縮小率は0~1の範囲で指定してください。デフォルト値(0.98)を使用します。" -ForegroundColor Yellow
                     $scaleFactor = 0.98
                 }
             } catch {
                 Write-Host "警告: 無効な入力です。デフォルト値(0.98)を使用します。" -ForegroundColor Yellow
                 $scaleFactor = 0.98
             }
         }
         
         Write-Host "縮小率 $($scaleFactor * 100)% で変換します" -ForegroundColor Yellow
         Process-TifFiles -SourceFolder $currentDir -OutputFolder $pdfFolder -ScaleFactor $scaleFactor -PaperSize $selectedPaperSize
     }
     "5" {
         # 用紙サイズ選択
         Write-Host "用紙サイズを選択してください:" -ForegroundColor Yellow
         $index = 1
         $sizeMap = @{}
         
         foreach ($size in $PAPER_SIZES.Keys) {
             Write-Host ("  " + $index + ": " + $size + " (" + $PAPER_SIZES[$size].Width + "mm × " + $PAPER_SIZES[$size].Height + "mm)") -ForegroundColor White
             $sizeMap[$index.ToString()] = $size
             $index++
         }
         
         $sizeOption = Read-Host "選択 [1]"
         if ([string]::IsNullOrWhiteSpace($sizeOption) -or -not $sizeMap.ContainsKey($sizeOption)) {
             $selectedPaperSize = "A3"  # デフォルト
         } else {
             $selectedPaperSize = $sizeMap[$sizeOption]
         }
         
         Write-Host "${selectedPaperSize}サイズで変換します" -ForegroundColor Yellow
         
         # スケール比の選択
         $scaleInput = Read-Host "縮小率を入力(精密変換には0.98-1.0を推奨)[0.99]"
         if ([string]::IsNullOrWhiteSpace($scaleInput)) {
             $scaleFactor = 0.99
         } else {
             try {
                 $scaleFactor = [double]$scaleInput
                 if ($scaleFactor -le 0 -or $scaleFactor -gt 1) {
                     Write-Host "警告: 縮小率は0~1の範囲で指定してください。デフォルト値(0.99)を使用します。" -ForegroundColor Yellow
                     $scaleFactor = 0.99
                 }
             } catch {
                 Write-Host "警告: 無効な入力です。デフォルト値(0.99)を使用します。" -ForegroundColor Yellow
                 $scaleFactor = 0.99
             }
         }
         
         Write-Host "縮小率 $($scaleFactor * 100)% で変換します" -ForegroundColor Yellow
         Process-TifFiles -SourceFolder $currentDir -OutputFolder $pdfFolder -ScaleFactor $scaleFactor -PreserveDpi -Verbose -PaperSize $selectedPaperSize
     }
     default {
         # 精密変換モード(元画像のDPIを維持)
         Write-Host "元画像のDPIを維持した精密変換を行います" -ForegroundColor Green
         
         # スケール比の選択
         $scaleInput = Read-Host "縮小率を入力(精密変換には0.98-1.0を推奨)[0.99]"
         if ([string]::IsNullOrWhiteSpace($scaleInput)) {
             $scaleFactor = 0.99
         } else {
             try {
                 $scaleFactor = [double]$scaleInput
                 if ($scaleFactor -le 0 -or $scaleFactor -gt 1) {
                     Write-Host "警告: 縮小率は0~1の範囲で指定してください。デフォルト値(0.99)を使用します。" -ForegroundColor Yellow
                     $scaleFactor = 0.99
                 }
             } catch {
                 Write-Host "警告: 無効な入力です。デフォルト値(0.99)を使用します。" -ForegroundColor Yellow
                 $scaleFactor = 0.99
             }
         }
         
         Write-Host "縮小率 $($scaleFactor * 100)% で変換します" -ForegroundColor Yellow
         Process-TifFiles -SourceFolder $currentDir -OutputFolder $pdfFolder -ScaleFactor $scaleFactor -PreserveDpi -Verbose -PaperSize $selectedPaperSize
     }
 }
}

# スクリプト実行
try {
 Start-Conversion
}
catch {
 Write-Host "エラーが発生しました: $_" -ForegroundColor Red
}
finally {
 Write-Host "処理を終了します。エンターキーを押すと終了します..." -ForegroundColor Yellow
 Read-Host
}

Discussion