全体フロー
Excel(コメント一覧)
↓ VBAマクロ実行(Alt+F8)
JavaScript コード生成 → クリップボードへ自動コピー
↓ PDF-XChange Editor で Ctrl+J → Ctrl+V → Enter
PDF 各ページにコメント追加完了 → Ctrl+S で保存
初回セットアップ(1回だけ)
コメント一覧_テンプレート_v3.xlsxを開く- Alt+F11(VBAエディタを開く)
- 挿入 → 標準モジュール
- VBAコードを貼り付け
- VBAエディタを閉じる
- 名前を付けて保存 → 種類を 「Excel マクロ有効ブック (.xlsm)」 で保存
毎回の操作
Step 1: Excel でデータ入力
「コメント一覧」シートに入力(1行目はヘッダー)
| A列(図番) | B列(コメント) |
|---|---|
| DWG-001 | 承認済み |
| DWG-002 | 要修正:寸法確認 |
※ 2行目 → PDFの1ページ目、3行目 → 2ページ目 … と対応
Step 2: 設定を調整(任意)
「設定」シートでドロップダウンから選択
| 項目 | 初期値 | 選択肢 |
|---|---|---|
| フォントサイズ | 10 | 8~14 推奨 |
| フォント | HelvB | HelvB / Helv / Cour / CourB / Times / TimesB |
| 文字色 | red | red / blue / black / green |
| 背景色 | white | white / yellow / none(透明) |
| 枠線 | なし | あり / なし |
| 枠線色 | black | red / blue / black / green |
| 位置 | 左上 | 左上 / 右上 / 左下 / 右下 |
Step 3: マクロ実行
Alt+F8 → 「JS生成_クリップボードコピー」→ 実行
→ JavaScriptが自動でクリップボードにコピーされる
Step 4: PDF-XChange Editor で貼り付け
- PDFを開く
- Ctrl+J(JSコンソールを開く)
- Ctrl+V(貼り付け)
- Enter(実行)→ 完了ダイアログ
- Ctrl+S(保存)
技術ポイント
VBAマクロの役割
- Excelの「コメント一覧」シートから図番・コメントを読み取り
- 「設定」シートからフォント・色・位置の設定を読み取り
- PDF-XChange Editor の JSコンソールで実行可能な JavaScript を自動生成
- 生成したコードをクリップボードにコピー
生成される JavaScript の処理内容
this.numPagesで PDF の総ページ数を取得- 各ページの寸法を
this.getPageBox("Crop", i)で取得 - テキスト幅を全角/半角で自動計算(全角=fontSize幅、半角=fontSize×0.55)
- 指定位置(左上/右上/左下/右下)に応じた座標を算出
this.addAnnot()で FreeText アノテーションとして追加
必要な環境
- Excel(マクロ有効)
- PDF-XChange Editor(無料版OK)
- 追加インストール:なし
Sub JS生成_クリップボードコピー()
'-------------------------------------------
' PDFコメント貼付ツール - JS生成マクロ(回転対応版)
'-------------------------------------------
Dim wsData As Worksheet
Dim wsSetting As Worksheet
Dim fontSize As Long
Dim textColor As String
Set wsData = ThisWorkbook.Sheets("コメント一覧")
' 設定読み込み
On Error Resume Next
Set wsSetting = ThisWorkbook.Sheets("設定")
On Error GoTo 0
If Not wsSetting Is Nothing Then
fontSize = wsSetting.Cells(2, 2).Value
textColor = CStr(wsSetting.Cells(3, 2).Value)
End If
If fontSize = 0 Then fontSize = 10
If textColor = "" Then textColor = "red"
' 色マッピング
Dim jsColor As String
Select Case LCase(textColor)
Case "red": jsColor = "color.red"
Case "blue": jsColor = "color.blue"
Case "black": jsColor = "color.black"
Case "green": jsColor = "color.green"
Case Else: jsColor = "color.red"
End Select
' データ読み込み
Dim row As Long
Dim dataCount As Long
row = 2
dataCount = 0
Do While wsData.Cells(row, 1).Value <> "" Or wsData.Cells(row, 2).Value <> ""
dataCount = dataCount + 1
row = row + 1
Loop
If dataCount = 0 Then
MsgBox "コメントデータがありません。" & vbCrLf & _
"「コメント一覧」シートの2行目以降にデータを入力してください。", vbExclamation
Exit Sub
End If
' JavaScript生成
Dim js As String
Dim Q As String
Q = Chr(34) ' ダブルクォート
js = "// PDF コメント貼付スクリプト(回転対応版)" & vbLf
js = js & "// 生成: " & Format(Now, "yyyy/mm/dd hh:nn:ss") & vbLf
js = js & "var comments = [" & vbLf
row = 2
Do While wsData.Cells(row, 1).Value <> "" Or wsData.Cells(row, 2).Value <> ""
Dim figNum As String
Dim comment As String
Dim displayText As String
figNum = CStr(wsData.Cells(row, 1).Value)
comment = CStr(wsData.Cells(row, 2).Value)
' エスケープ
displayText = Replace(comment, "\", "\\")
displayText = Replace(displayText, Q, "\" & Q)
If figNum <> "" Then
figNum = Replace(figNum, "\", "\\")
figNum = Replace(figNum, Q, "\" & Q)
displayText = "[" & figNum & "] " & displayText
End If
js = js & " " & Q & displayText & Q & "," & vbLf
row = row + 1
Loop
js = js & "];" & vbLf
js = js & "" & vbLf
' ============================================================
' 回転対応のコアロジック
' getPageBox は「PDFの生座標系(回転前)」を返す
' getPageRotation で回転角を取得し、座標を補正する
'
' 各回転角での座標変換:
' 回転0° : そのまま。左上 = (x0, y1)
' 回転90° : 幅と高さが入れ替わる。左上 = (y0, x1)
' 回転180°: 左上が右下になる。左上 = (x1, y0)
' 回転270°: 幅と高さが入れ替わり反転。左上 = (y1, x0)
'
' 目標:どの回転でも「表示上の左上端」にコメントを配置する
' ============================================================
js = js & "// ページ回転を考慮してrectを計算するヘルパー関数" & vbLf
js = js & "function calcRect(box, rotation, textLen, fSize) {" & vbLf
js = js & " // box = [x0, y0, x1, y1] (PDF生座標系、左下原点)" & vbLf
js = js & " // x0,y0=左下 x1,y1=右上" & vbLf
js = js & " var x0 = box[0], y0 = box[1], x1 = box[2], y1 = box[3];" & vbLf
js = js & " var w = x1 - x0; // ページ幅(生座標)" & vbLf
js = js & " var h = y1 - y0; // ページ高さ(生座標)" & vbLf
js = js & " var margin = 8;" & vbLf
js = js & " var tW = textLen * fSize * 0.55;" & vbLf
js = js & " var tH = fSize + 4;" & vbLf
js = js & " var rx0, ry0, rx1, ry1;" & vbLf
js = js & " // 「表示上の左上」を生座標に変換してrectを組み立てる" & vbLf
js = js & " if (rotation === 0) {" & vbLf
js = js & " // 表示: 左上 = PDF座標(x0, y1)" & vbLf
js = js & " rx0 = x0 + margin;" & vbLf
js = js & " ry1 = y1 - margin;" & vbLf
js = js & " rx1 = rx0 + tW;" & vbLf
js = js & " ry0 = ry1 - tH;" & vbLf
js = js & " } else if (rotation === 90) {" & vbLf
js = js & " // 表示: 左上 = PDF座標(x0, y0) ※幅と高さが見かけ上入れ替わる" & vbLf
js = js & " rx0 = x0 + margin;" & vbLf
js = js & " ry0 = y0 + margin;" & vbLf
js = js & " rx1 = rx0 + tH;" & vbLf
js = js & " ry1 = ry0 + tW;" & vbLf
js = js & " } else if (rotation === 180) {" & vbLf
js = js & " // 表示: 左上 = PDF座標(x1, y0)" & vbLf
js = js & " rx1 = x1 - margin;" & vbLf
js = js & " ry0 = y0 + margin;" & vbLf
js = js & " rx0 = rx1 - tW;" & vbLf
js = js & " ry1 = ry0 + tH;" & vbLf
js = js & " } else if (rotation === 270) {" & vbLf
js = js & " // 表示: 左上 = PDF座標(x1, y1) ※幅と高さが見かけ上入れ替わる" & vbLf
js = js & " rx1 = x1 - margin;" & vbLf
js = js & " ry1 = y1 - margin;" & vbLf
js = js & " rx0 = rx1 - tH;" & vbLf
js = js & " ry0 = ry1 - tW;" & vbLf
js = js & " } else {" & vbLf
js = js & " // フォールバック(想定外の回転値)" & vbLf
js = js & " rx0 = x0 + margin;" & vbLf
js = js & " ry1 = y1 - margin;" & vbLf
js = js & " rx1 = rx0 + tW;" & vbLf
js = js & " ry0 = ry1 - tH;" & vbLf
js = js & " }" & vbLf
js = js & " return [rx0, ry0, rx1, ry1];" & vbLf
js = js & "}" & vbLf
js = js & "" & vbLf
js = js & "var n = this.numPages;" & vbLf
js = js & "var added = 0;" & vbLf
js = js & "for (var i = 0; i " & Chr(60) & " n " & Chr(38) & Chr(38) & " i " & Chr(60) & " comments.length; i++) {" & vbLf
js = js & " if (comments[i] === " & Q & Q & ") continue;" & vbLf
js = js & " var page = this.getPageBox(" & Q & "Crop" & Q & ", i);" & vbLf
js = js & " var rot = this.getPageRotation(i); // 0, 90, 180, 270 のいずれか" & vbLf
js = js & " var tLen = comments[i].length;" & vbLf
js = js & " var r = calcRect(page, rot, tLen, " & fontSize & ");" & vbLf
js = js & " this.addAnnot({" & vbLf
js = js & " type: " & Q & "FreeText" & Q & "," & vbLf
js = js & " page: i," & vbLf
js = js & " rect: r," & vbLf
js = js & " contents: comments[i]," & vbLf
js = js & " textFont: font.HelvB," & vbLf
js = js & " textSize: " & fontSize & "," & vbLf
js = js & " textColor: " & jsColor & "," & vbLf
js = js & " strokeColor: [" & Q & "RGB" & Q & ",1,1,1]," & vbLf
js = js & " fillColor: [" & Q & "RGB" & Q & ",1,1,1]," & vbLf
js = js & " opacity: 0.9," & vbLf
js = js & " borderEffectStyle: " & Q & Q & "," & vbLf
js = js & " width: 0" & vbLf
js = js & " });" & vbLf
js = js & " added++;" & vbLf
js = js & "}" & vbLf
js = js & "app.alert(" & Q & "完了! " & Q & "+added+" & Q & " ページにコメントを追加しました。\nCtrl+S で保存してください。" & Q & ", 3);" & vbLf
' クリップボードにコピー(MSForms.DataObject使用)
Dim objData As Object
Set objData = CreateObject("new:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
objData.SetText js
objData.PutInClipboard
Set objData = Nothing
MsgBox dataCount & " 件のコメントからJavaScriptを生成しました!(回転対応版)" & vbCrLf & vbCrLf & _
"クリップボードにコピー済みです。" & vbCrLf & vbCrLf & _
"【次の手順】" & vbCrLf & _
"1. PDF-XChange Editor でPDFを開く" & vbCrLf & _
"2. Ctrl+J (JSコンソール)" & vbCrLf & _
"3. Ctrl+V (貼り付け)" & vbCrLf & _
"4. Enter (実行)" & vbCrLf & _
"5. Ctrl+S (保存)", vbInformation, "PDF コメント貼付ツール(回転対応版)"
End Sub

コメント