0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Python で Word 文書のヘッダーとフッターを一括設定する

0
Posted at

社外へ配布する Word 文書にとって、ヘッダーとフッターは名刺のようなものです。ページ番号は引用・指定の場所として機能し、会社ロゴや「社外秘」の表示は文書の識別と情報管理を担います。1 通の文書に手動でヘッダーを付けるのは難しくありません。難しいのは一貫性を保つことです。数十通の報告書でヘッダー書式を統一し、表紙にはページ番号を出さず、両面印刷ではページ番号を常に外側に置く——こうした細部の手動運用は時間がかかるうえに漏れが出ます。コードに任せれば、一度の設定を使い回せます。

本記事では Free Spire.Doc for Python を使って、ヘッダー・フッターの一連の設定を解説します。テキストヘッダーとページ番号フィールドの基本、表紙ページの独立処理、偶数・奇数ページの切り替え、ロゴ画像を置く 2 つの方法、クロス文書への書式統一、そして配布前のヘッダーロックまで扱います。

pip install spire.doc.free

デモの入力は 2 つのファイルです。業務報告書.docx(4 ページ、1 ページ目が表紙、以降 3 ページの本文、財務データの表を含む)と、旧版報告書.docx(2 ページの履歴文書、ヘッダー・フッターなし)。

元の表紙


まず押さえる 2 つの既定値

ヘッダーとフッターのレイアウトは PageSetup の 2 つの距離パラメータで制御されます。HeaderDistance はページ上端からヘッダー開始位置まで、FooterDistance はページ下端からフッター開始位置までの距離で、新規文書の既定値はどちらも 36.0 pt です。

この既定値と余白の関係がヘッダーの利用可能な高さを決めます。本文領域は上余白 72 pt から始まり、ヘッダーは 36 pt から始まるため、両者の間の約 36 pt がヘッダーの実質的な利用高さです。9 pt の小さな文字 1 行と区切り線なら十分ですが、背の高い画像を置くとヘッダー領域に入りきらず本文が下に押し出されます。後述するロゴの 2 つの置き方が結果として分かれる理由がここにあります。


基本のヘッダー・フッター:テキストヘッダーとページ番号フィールド

Section.HeadersFooters の下に Header と Footer の 2 つのコンテナがあり、それぞれ AddParagraph で通常の段落としてレイアウトします。ページ番号はフィールドで挿入します。FieldPage が現在ページ、FieldNumPages が総ページ数です。

from spire.doc import *
from spire.doc.common import *

document = Document()
document.LoadFromFile("業務報告書.docx")
section = document.Sections[0]

# ヘッダー:会社名 + 報告書名、グレー 9pt、下罫線 1 本
header_paragraph = section.HeadersFooters.Header.AddParagraph()
tr = header_paragraph.AppendText("北星テクノロジー · 2026年度 第2四半期 業務報告書")
tr.CharacterFormat.FontName = "Yu Gothic"
tr.CharacterFormat.FontSize = 9
tr.CharacterFormat.TextColor = Color.FromArgb(255, 110, 116, 124)
header_paragraph.Format.Borders.Bottom.BorderType = BorderStyle.Single
header_paragraph.Format.Borders.Bottom.Space = 1.0

# フッター:X / Y ページ(フィールド)、右寄せ、上罫線 1 本
footer_paragraph = section.HeadersFooters.Footer.AddParagraph()
footer_paragraph.Format.HorizontalAlignment = HorizontalAlignment.Right
footer_paragraph.AppendField("page number", FieldType.FieldPage)
footer_paragraph.AppendText(" / ")
footer_paragraph.AppendField("number of pages", FieldType.FieldNumPages)
footer_paragraph.AppendText(" ページ")

フィールド部分の文字書式は別途設定が必要です。AppendField が返すのはフィールドオブジェクトであり AppendText のような TextRange ではないため、「X / Y ページ」の「ページ」などの文字は AppendText の戻り値で書式を設定し、フィールド自体のフォントは挿入後に段落の ChildObjects を走査して DocumentObjectType.TextRange 型のオブジェクトへ 1 つずつ設定します。フィールドが評価された後の文字も TextRange に含まれるためです。

for k in range(footer_paragraph.ChildObjects.Count):
    obj = footer_paragraph.ChildObjects.get_Item(k)
    if obj.DocumentObjectType == DocumentObjectType.TextRange:
        obj.CharacterFormat.FontName = "Yu Gothic"
        obj.CharacterFormat.FontSize = 9
        obj.CharacterFormat.TextColor = Color.FromArgb(255, 110, 116, 124)

ページ番号はフィールドでなければなりません。この報告書は 4 ページなので「1 / 4」と手入力しても一見動きますが、本文を 1 ページ増減した瞬間に全ページの数字が狂います。フィールドは文書を開くたび・レンダリングするたびに再評価されるため、ページ番号は常に正確です。出力のレンダリングでフッターに「2 / 4 ページ」と表示され、2 つのフィールドが正しく評価されていることを確認できます。

基本ヘッダー・フッターの効果


表紙ページ:先頭ページを独立させ空白を保つ

表紙付きの報告書で、表紙にヘッダーやページ番号を出すべきではありません。PageSetup.DifferentFirstPageHeaderFooter を有効にすると、1 ページ目は FirstPageHeader と FirstPageFooter の独立したコンテナを使い、それ以外のページは通常の Header / Footer を使い続けます。

document = Document()
document.LoadFromFile("業務報告書_基本ヘッダー.docx")
section = document.Sections[0]

# 「先頭ページのみ別」を有効化
section.PageSetup.DifferentFirstPageHeaderFooter = True

# FirstPageHeader / FirstPageFooter に何も追加しなければ表紙は空白のまま

ここで「クリア」操作は不要です。FirstPageHeader は独立コンテナなので、空のまま放置すれば表紙は空白になり、通常ヘッダーには影響しません。保存後の確認では FirstPageHeader・FirstPageFooter の段落数はどちらも 0、表紙ページのレンダリングにも罫線・ページ番号がなく、2 ページ目以降のヘッダー・フッターはそのまま残っています。

表紙が空白になった様子


偶数・奇数ページ:両面印刷に備える

報告書を両面印刷して製本するとき、ページ番号は常に外側——奇数ページ(右ページ)では右寄り、偶数ページ(左ページ)では左寄り——にあると読みやすいものです。「社外秘」の表示を偶数ページのヘッダーにだけ置く運用もよく見られます。これには 2 つ目のスイッチ DifferentOddAndEvenPagesHeaderFooter を使います。2 つのスイッチは重ねて有効にできます。

document = Document()
document.LoadFromFile("業務報告書_基本ヘッダー.docx")
section = document.Sections[0]

# 表紙は空白 + 偶数・奇数ページで切り替え、スイッチを重ねる
section.PageSetup.DifferentFirstPageHeaderFooter = True
section.PageSetup.DifferentOddAndEvenPagesHeaderFooter = True

# スイッチを有効にすると、既存の Header/Footer は奇数ページにのみ作用する
# 偶数ページのヘッダー:区分表示、右寄せ(外側)
even_header = section.HeadersFooters.EvenHeader.AddParagraph()
even_header.Format.HorizontalAlignment = HorizontalAlignment.Right
tr = even_header.AppendText("北星テクノロジー · 社外秘")
tr.CharacterFormat.FontName = "Yu Gothic"
tr.CharacterFormat.FontSize = 9
tr.CharacterFormat.TextColor = Color.FromArgb(255, 110, 116, 124)
even_header.Format.Borders.Bottom.BorderType = BorderStyle.Single

# 偶数ページのフッター:ページ番号は左寄せ(外側)
even_footer = section.HeadersFooters.EvenFooter.AddParagraph()
even_footer.Format.HorizontalAlignment = HorizontalAlignment.Left
even_footer.AppendField("page number", FieldType.FieldPage)
even_footer.AppendText(" / ")
even_footer.AppendField("number of pages", FieldType.FieldNumPages)

スイッチの意味は誤解しやすい点です。偶数・奇数の切り替えを有効にすると、それまで Header / Footer に設定した内容は奇数ページにのみ作用し、偶数ページは EvenHeader / EvenFooter に別途書き込む必要があります。書き漏らすと偶数ページのヘッダーは消えます。奇数ページの設定を引き継ぐわけではありません。レンダリングで確認すると、2 ページ目(偶数)はヘッダー「北星テクノロジー · 社外秘」・ページ番号「2 / 4 ページ」が左寄り、3 ページ目(奇数)はヘッダーが報告書名・ページ番号「3 / 4 ページ」が右寄りになります。

偶数・奇数ページの効果


ロゴヘッダー:インラインとフローティングは別物

会社ロゴをヘッダーに置く方法は 2 つあり、結果は大きく異なります。AppendPicture が返す DocPicture は Width / Height で表示サイズを設定でき、元画像 800 × 200 px は 1/4 の 200 × 50 pt に縮小して表示します。

インライン画像はヘッダー段落の文字組みに参加し、ヘッダー行の高さは画像の高さまで広がります。

header_paragraph = section.HeadersFooters.Header.AddParagraph()
pic = header_paragraph.AppendPicture("北星テクノロジー_ロゴ.png")
pic.Width = 200.0     # 表示サイズ 200 × 50 pt
pic.Height = 50.0
header_paragraph.Format.Borders.Bottom.BorderType = BorderStyle.Single

フローティング画像は折り返しを Behind(テキストの背面)、配置の基準をページに変更します。画像は文字流から外れ、ヘッダー行の高さを消費しなくなります。

pic = header_paragraph.AppendPicture("北星テクノロジー_ロゴ.png")
pic.TextWrappingStyle = TextWrappingStyle.Behind
pic.HorizontalOrigin = HorizontalOrigin.Page       # 水平配置の基準:ページ左端
pic.VerticalOrigin = VerticalOrigin.Page           # 垂直配置の基準:ページ上端
pic.VerticalAlignment = ShapeVerticalAlignment.Top
pic.Width = 200.0
pic.Height = 50.0

2 つの置き方の違いは本文の開始位置で定量化できます。レンダリング画像で本文最初の行の墨が現れる位置は、インライン版が 61 行目・フローティング版が 13 行目でした。インラインではロゴの 50 pt がそのまま本文の下がりになり、フローティングではまったく版面を消費しません。ロゴが装飾要素ならフローティング、ヘッダーで完全な企業識別の帯を示すならインラインが適します。元画像は表示サイズの整数倍(ここでは 4 倍)で用意すると、縮小時のジャギーを避けられます。

インラインとフローティングのロゴ比較


クロス文書の統一:Clone が必須

既存文書にはヘッダーがなく、1 通ずつ設定し直すのは現実的ではありません。整えた 1 通をテンプレートにして、ヘッダー・フッターのオブジェクトを複製するのが正攻法です。

source = Document()
source.LoadFromFile("業務報告書_基本ヘッダー.docx")
src_header = source.Sections[0].HeadersFooters.Header
src_footer = source.Sections[0].HeadersFooters.Footer

target = Document()
target.LoadFromFile("旧版報告書.docx")

for i in range(target.Sections.Count):
    section = target.Sections.get_Item(i)
    for j in range(src_header.ChildObjects.Count):
        obj = src_header.ChildObjects.get_Item(j)
        section.HeadersFooters.Header.ChildObjects.Add(obj.Clone())
    for j in range(src_footer.ChildObjects.Count):
        obj = src_footer.ChildObjects.get_Item(j)
        section.HeadersFooters.Footer.ChildObjects.Add(obj.Clone())

文書をまたぐ複製では Clone() が必須です。ヘッダーの段落オブジェクトは元文書のオブジェクトツリーに属しており、元オブジェクトを直接 Add すると 2 つの文書が同じメモリを共有し、保存時に内容が崩れます。Clone は深いコピーを生成し、それぞれ独立させます。今回の実行ではヘッダーオブジェクト 1 個・フッターオブジェクト 1 個(各 1 段落)を複製し、旧版報告書.docx の 1 ページ目にヘッダー罫線とフッター「1 / 2 ページ」が現れることをレンダリングで確認しました。

履歴文書のヘッダー統一


配布前のヘッダーロック

ヘッダー・フッターを整えた後、本文は他の人がデータを追記する必要がある一方、「社外秘」表示やロゴは勝手に変更させたくないものです。フォーム保護とセクション単位の免除を組み合わせて「本文は編集可・ヘッダーフッターはロック」を実現します。

document = Document()
document.LoadFromFile("業務報告書_基本ヘッダー.docx")
section = document.Sections[0]

# 文書全体を「フォームフィールドのみ入力可」で保護(このタイプではヘッダー・フッターが編集不可)
document.Protect(ProtectionType.AllowOnlyFormFields, "HOKU2026")
# セクション 1 をフォーム保護から免除:本文は編集可能のまま
section.ProtectForm = False

Protect の第 1 引数に AllowOnlyFormFields を選ぶのは、セクション単位の免除と組み合わせられるためです。ProtectForm = False にしたセクションでは本文を自由に編集でき、ヘッダー・フッターは免除の対象外なのでロックされたままです。保存後に読み込み直して検証すると、GetProtectionType() は AllowOnlyFormFields、セクション 1 の ProtectForm は False で設定どおりです。レンダリング上の見た目は無保護版と完全に同じで、保護は表示に影響しません。


適用場面と組み込み方

この設定チェーンが向くのは 2 つの場面です。1 つは報告書の一括生成の最終工程です。上流システムが本文を出力した後、文書種別に応じたヘッダー設定を適用します。社外向け報告書にはフローティングのロゴとページ番号フィールド、社内資料には「社外秘」表示と偶数・奇数ページのページ番号、という使い分けです。もう 1 つは既存文書の標準化です。引継ぎ・保管・監査対応の前に、Clone による複製で履歴文書を同じヘッダーテンプレートに統一します。1 通ずつ開いて手設定する必要はありません。

設定自体はコードから分離するのがよい扱いです。ヘッダー文字列・フォント色・ロゴのパス・使うスイッチの組み合わせを JSON や YAML の設定ファイルに置き、スクリプトは読み取った設定で文書種別ごとのテンプレートを選ぶ。報告書の規格が増えるたびに設定だけ追加し、コードは変えません。ロックは文書を外へ出す直前にだけ実行し、パスワードは配布フローで一元管理します。

本記事の操作とレンダリング出力はすべて Free Spire.Doc for Python 環境で実測しています。文書の読み込み、ヘッダー・フッターの読み書き、画像挿入、保護のいずれも無料版で利用できる機能です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?