社外へ配布する 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 環境で実測しています。文書の読み込み、ヘッダー・フッターの読み書き、画像挿入、保護のいずれも無料版で利用できる機能です。





