OneDriveの「重要なフォルダーの保護」を停止すると、重要なフォルダーからファイルが消える話

「オンラインストレージサーヴィスで同期を解除するとローカルファイルが削除される」と言うのはよく聞く罠ですが、それがWindows 10の「重要なフォルダーの保護」でも発生するため、注意喚起としてこの記事を書きました

オンラインストレージサーヴィスで同期を解除したりアカウントを削除すると同期していたローカルファイルが削除される、と言う挙動自体はOneDrive以外でもありがちな挙動ですが (私はこの挙動自体どうかと思いますが、それはそれとして)、それが重要なフォルダー (デスクトップ、ピクチャー、ドキュメント) で発生するので知らないと問題が発生しかねないと懸念し、詳細情報として再現手順を以下に説明します


追記

本事象について、筆者自身がWindows 10 October 2018 Updateの最初のリリース直後に気づき記事にしたこともあり、Windows 10 October 2018 Updateによりユーザーデータが消える事象を連想してしまいますが、本件は別事象となります

しかし、Windows 10 October 2018 Updateの最初のリリースにてユーザーデータが消える事象自体と、本件で問題視している「重要なフォルダーの保護」機能自体は関連があります (ややこしい)

Windows 10 October 2018 Updateの最初のリリースにてユーザーデータが消える事象についての詳細については Updated version of Windows 10 October 2018 Update released to Windows Insiders - Windows Experience BlogWindows Experience Blog をご覧ください


再現手順

対象フォルダ (今回はデスクトップ) のファイルの確認

今回はデスクトップにテストデータとして 新しいテキスト ドキュメント.txt を用意しました

OneDriveの「重要なフォルダーの保護」でデスクトップを保護する

  1. タスクバーのOneDriveアイコンから「その他」、「設定」を選択する
  2. 表示されたMicrosoft OneDrive画面から「自動保存」タブを選択し、「重要なフォルダーを保護する」の「フォルダーの更新」ボタンを押す
  3. 表示された「重要なフォルダーの保護を設定」画面で (デフォルトで、デスクトップ、写真、ドキュメントがチェックされているので) 今回はデスクトップのみをチェックした状態にし、「保護の開始」ボタンを押す
  4. デスクトップ上の 新しいテキスト ドキュメント.txt にOneDriveで同期されているファイルに付くチェックアイコンが付いたことを確認する

デスクトップの「重要なフォルダーの保護」を停止とファイルの確認

  1. 再び「重要なフォルダーの保護を設定」画面を表示し、デスクトップの項目の「保護の停止」を押す
  2. 保護を無効にしますか?
    ・デスクトップのすべてのアイテムは OneDriveに残ります。
    ・新しいファイルは、OneDriveで保護されていない別のフォルダーに追加されます。

    と言う文言を確認し「保護の停止」をクリックする
  3. デスクトップ上のファイルが消え、ファイルの場所 と言うOneDriveでデスクトップファイルを同期していたフォルダーへのショートカットが作成されていることを確認する
  4. なお、ファイルの場所 からOneDriveでデスクトップファイルを同期していたフォルダーへ移動すれば、デスクトップ上から消されたファイルを得る事が出来ます

OneDriveへの要望

「重要なフォルダーの保護」でフォルダーを保護した後、保護の停止を行うと、「重要なフォルダー」からファイルが消されるが、消さないよう変更すべきである

まず、保護の停止時に表示される説明からファイルの削除を読み取ることが出来ない

また、説明があっても重要なフォルダー(特にドキュメントフォルダー)にはアプリケーションの設定ファイル等を保存されている場合があり、一時的にでもファイルが削除されると障害を招きかねない

よって、少なくともファイルを消さずに保護を無効にする方法を用意し、デフォルトとすべきである

.NETの System.Io.Compression で非圧縮のZIPファイルを作れなかったが対象が固定だったので直接バイナリファイル作って強引に解決した話

この話は件名が全てなので、タイトルを読んで「ああ、そうですね」と思った人は読んでも新たな知見は得られません

EPUBファイルを作るためにmimetypeを非圧縮でZIP化したいが System.Io.Compression で上手く出来ない

EPUBの仕様ではmimetyeファイルは非圧縮でzipファイルの最初に格納されていなければなりません

さらに mimetype ファイルは、圧縮または暗号化をしてはならず(must)、そして ZIP ヘッダにエキストラフィールドがあってはならない(must not)。

3.3 OCF ZIP コンテナのメディアタイプの識別 - PUB Open Container Format (OCF) 3.0.1(日本語訳版)

そこで .NETSystem.Io.Compression 名前空間を使ってみます

ZipFileExtensionsCreateEntryFromFile メソッドに [CompressionLevel]::NoCompression を指定して圧縮するPowerShellを書いてみます

using namespace System.IO.Compression;

[ZipArchive] $zipArchive = [ZipFile]::Open('sample.epub',[ZipArchiveMode]::Update);

[ZipFileExtensions]::CreateEntryFromFile($zipArchive, 'mimetype', 'mimetype', [CompressionLevel]::NoCompression) > $null;

$zipArchive.Dispose();

しかし、確認してみると mimetype ファイルは Deflate で圧縮されてしまっています

駄目じゃん

と言う訳で圧縮済みのZIPをバイナリファイルとして直接作ることにした

ZIP化の対象ファイルが可変の内容であれば別なツールを使うか、最悪 ZIP File Format Specification を読む羽目になっていたところですが、今回対象としているEPUBmimetye ファイルは幸い内容が完全固定で、しかも小さいです

つまり、最初からZIP化済みのファイルを用意しておいて複製して使ったり、或いは固定のZIP化したバイナリィデータを知っておけばそれを書き込んで直接ZIPファイルを生成したりして今回はこの問題を回避できます

てな訳で、以下のコードで問題回避

[Byte[]] $byteData = ('80', '75', '3', '4', '10', '0', '0', '0', '0', '0', '99', '140', '53', '77', '111', '97', '171', '44', '20', '0', '0', '0', '20', '0', '0', '0', '8', '0', '0', '0', '109', '105', '109', '101', '116', '121', '112', '101', '97', '112', '112', '108', '105', '99', '97', '116', '105', '111', '110', '47', '101', '112', '117', '98', '43', '122', '105', '112', '80', '75', '1', '2', '30', '3', '10', '0', '0', '0', '0', '0', '99', '140', '53', '77', '111', '97', '171', '44', '20', '0', '0', '0', '20', '0', '0', '0', '8', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '255', '129', '0', '0', '0', '0', '109', '105', '109', '101', '116', '121', '112', '101', '80', '75', '5', '6', '0', '0', '0', '0', '1', '0', '1', '0', '54', '0', '0', '0', '58', '0', '0', '0', '0', '0');

[System.IO.File]::WriteAllBytes("./sample.epub", $byteData);

バイナリファイルの保存はWindows PowerShellなら Set-Content './sample.epub' -Value $byteData -Encoding Byte;PowerShell Coreなら Set-Content -Path './sample.epub' -Value $byteData -AsByteStream; でも行ける感じです

我ながら強引ですが、そんな感じで一つ

2018年の抱負の進捗状況 (10月1日時点)

この記事は自分向けの記事です

もうちょっと頻繁にblogを更新する

毎月、この進捗以外に何か記事は公開できているので、無理せずこんな感じで

暫くはEPUB関連の記事になりそうです

体重を60kgまで落とす、改め体重60kg前後を維持する

の朝が59.90kgでの朝が61.10kgでした

最近は60.00kgから61.50kgの間をうろうろしています

もう少し減らしたいところではあるのですが、一方でリバウンドと騒ぐほどでもなく、体脂肪率は9.0%から10%程度を保って安定しているのでこんな感じでもいいかともったりもしています


また、からNHKみんなで筋肉体操を2日に1回やるようにしました

最初は全然できなかったり、翌日筋肉痛で苦しんだりしましたが最近は一応一通りの運動ができるようになりました

始めて1か月未満なので見た目や数字には全然結果が表れていませんが、仮に結果が現れなくてもやらないよりやっている方が健康的だと思うのでしばらく続けてみます

HTML5.2の仕様書を一通り読む、改め HTML LS Developer's Editionを読む

準備だけはじめていますが、まだ表に出せていません

表に出さないとやる気が維持できないので、年内には途中でも何でも何かを表に出して、来年あたりから本気で注力したいところです

仕様書読むのってマラソンだな、と最近認識を新たにしております

応用情報技術者試験に合格する、改め情報処理安全確保支援士を受験する

試験実施日はになります

今のところ記念受験になりそうな感じです

また来年

PowerShell 6.1のConvertFrom-Markdownを使ってMarkdownファイルからHTMLファイルを生成してみる

PowerShell 6.1を導入したので、追加されたConvertFrom-MarkdownコマンドレットでMarkdownファイルからHTMLファイルを生成してみます

Markdown系のコマンドレットを確認する

とりあえず Get-HelpConvertFrom-Markdown のパラメータとか戻り値とか確認してみます

pwsh >Get-Help -Name 'ConvertFrom-Markdown'

NAME
    ConvertFrom-Markdown

SYNTAX
    ConvertFrom-Markdown [-Path] <string[]> [-AsVT100EncodedString] [<CommonParameters>]

    ConvertFrom-Markdown -LiteralPath <string[]> [-AsVT100EncodedString] [<CommonParameters>]

    ConvertFrom-Markdown -InputObject <psobject> [-AsVT100EncodedString] [<CommonParameters>]

(以下略)

ざっくり -PathMarkdown ファイル渡せばいいらしいです

ちなみに Get-Help ConvertFrom-Markdown -Online を実行したら https://docs.microsoft.com/ja-jp/powershell/module/Microsoft.PowerShell.Utility/ConvertFrom-Markdown に行けますが、現時点では 404 Not Foundだそうです

実際に動かしてみる

sample.md という名前で以下の様なファイルを用意して

# サンプルマークダウンファイル

これはサンプル用のマークダウンファイルです

[example.com](http://example.com)

ConvertFrom-Markdown-Path に渡してやります

pwsh >[Microsoft.PowerShell.MarkdownRender.MarkdownInfo] $md = ConvertFrom-Markdown -Path 'sample.md';
pwsh >Format-List -InputObject $md;

Html               : <h1 id="section">サンプルマークダウンファイル</h1>
                     <p>これはサンプル用のマークダウンファイルです</p>
                     <p><a href="http://example.com">example.com</a></p>

VT100EncodedString :
Tokens             : {Markdig.Syntax.HeadingBlock, Markdig.Syntax.ParagraphBlock, Markdig.Syntax.ParagraphBlock, Markdig.Extensions.AutoIdentifiers.HeadingLinkReferenceDefinition}

pwsh >$md.Html;
<h1 id="section">サンプルマークダウンファイル</h1>
<p>これはサンプル用のマークダウンファイルです</p>
<p><a href="http://example.com">example.com</a></p>

戻り値の PowerShell.MarkdownRender.MarkdownInfo オブジェクトの Html プロパティにbody要素の内容となる文字列が格納されているようです

ちなみに、void要素があった場合、XMLとしてはパースエラーになりますので ('<root>',$md.Html,'</root>' -Join '') -as [Xml.XmlDocument] とかやっても null が帰ってきます

ここで「じゃあvoid要素がったら終了タグを追加して」とかやりだすと話が大きくなるので今回は雑に行きます

pwsh >'<!DOCTYPE html><html><head><meta charset="utf-8"><title>sample</title></head><body>' + $md.html + '</body></html>' > sample.html;

我ながら本当に雑だな、おい

PowerShell 6.x からはリダイレクト演算子 (>) で出力したテキストファイルは UTF-8 (BOMなし) で出力されますのでHTMLファイルならこれでいでいけます (ちなみに PowerShell 5.1 までは UTF-16 でした)


上記のままだと html 要素に lang 属性がないとか、title 要素が固定とか、出力ファイル名が固定とか色々ありますので、欲しい機能を色々足せば完成です

そんな感じで

PowerShell 6.1をWindows 10に導入したので覚書

PowerShell 6.1をWindows 10端末に導入したので覚書

参考サイト、文献

導入に当たっては以下のサイト、書籍を参考にしました

身も蓋もありませんが、より深く理解したい人やmacOSLinuxに導入したい人は、この記事読むより上記のサイト、書籍を読んで下さい

PowerShell Core のサポート ライフサイクル

PowerShell 6.xを導入するにあたっては PowerShell Core のサポート ライフサイクル | Microsoft Docs を把握しておくことをお勧めします

最新の PowerShell 6.x のインストーラをダウンロードして実行

Releases · PowerShell/PowerShell · GitHub からインストーラーをダウンロード (自分は64bit版Windows 10なので PowerShell-6.1.0-win-x64.msi)

インストーラの実行は特に迷うところもないので省略

規定値では %ProgramFiles%\PowerShell\6\PowerShellがインストールされ、実行ファイルは pwsh.exe になります

また、インストーラがシステム環境変数PATH に上記pathを追加するので以降 pwsh で PowerShell 6.xが呼び出せるようになります

ターミナルからバージョンの確認

コマンドプロンプトからはpwsh --version でpwsh.exeのバージョンが、また --command で従来のWindows PowerShellpowershell 同様にPowerShellのコマンドが実行できます

cmd >pwsh --version
PowerShell 6.1.0

cmd >pwsh -command $PSVersionTable.PSVersion

Major  Minor  Patch  PreReleaseLabel BuildLabel
-----  -----  -----  --------------- ----------
6      1      0

Windows PowerShell 5以前との共存を確認

(従来通り) Windows PowerShell (v5.1 or less than...) を呼び出すときは powershell コマンドを使います

cmd >powershell -command $PSVersionTable.PSVersion

Major  Minor  Build  Revision
-----  -----  -----  --------
5      1      17134  228

また、(従来通り) -Version オプションを使うことで古いバージョンのPowerShellを起動することもできます

cmd >powershell -Version 2.0 -command $PSVersionTable.CLRVersion

Major  Minor  Build  Revision
-----  -----  -----  --------
2      0      50727  8935

Visual Studio Codeの設定変更

PowerShell 6.1にはWindows PowerShellで言う所のISEはないのでIDEにはVisual Studio CodePowerShell拡張の使用をお勧めします

まず、Visual Studio Codeをインストールし、PowerShell拡張を導入しておきます

その上で標準ターミナルをPowerShell 6.xにするため、Visual Studio Codeのユーザー設定またはワークスペース設定のTerminal › Integrated › Shell: WindowsC:\Program Files\PowerShell\6\pwsh.exe に変更します

setting.jsonを直接編集する場合、以下の通りです

  // Windows でターミナルが使用するシェルのパス。[シェルの構成について詳細を表示](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration)。
  "terminal.integrated.shell.windows": "C:\\Program Files\\PowerShell\\6\\pwsh.exe"

ちなみにユーザー設定のsetting.jsonを直接編集したい場合、setting.json%APPDATA%\Code\User\setting.json に存在します


また、PowerShell拡張で使用するPowerShellは上記標準ターミナルの設定とは別にPowershell: Power Shell Exe Pathを C:\Program Files\PowerShell\6\pwsh.exe に変更します

setting.jsonを直接編集する場合、以下の通りです

  // Specifies the full path to a PowerShell executable. Changes the installation of PowerShell used for language and debugging services.
  "powershell.powerShellExePath": "C:\\Program Files\\PowerShell\\6\\pwsh.exe"

この設定を行わないと標準ターミナルは6.xでも、PowerShell拡張は5.1で実行されてしまいます (1敗)


おまけ: .NET CoreのSDKも導入

.NET CoreのSDK .NET Framework や別バージョンの .NET Core と共存できます

.NET Downloads for Linux, macOS, and Windows

自分の環境用のインストーラをダウンロードしたら実行します

完了したらインストール状況を確認

cmd >dotnet --version
2.1.402
cmd >dotnet --info
.NET Core SDK (global.json を反映):
 Version:   2.1.402
 Commit:    3599f217f4

(以下略)

以上になります

自分用同人小説を縦書きEpubファイルにするための作業手順

この記事は、自分の試行錯誤の垂れ流しなので、いつも以上に突っ込み歓迎です

本手順書でEPUBと称しているファイルはEPUB Validator (beta)EPUB 3.0.1で合格できるものであり、EPUBファイルとして仕様に準拠している保証はありません

自分用同人小説を縦書きEPUBファイルにするための作業手順を書き留めておきます

本手順はあくまで自分 (木俣) 用ですのでご注意ください

ディレクトリィ構造を作る

今回作成するEPUBファイルの用のディレクトリィを用意し (以下、「EPUB ルートディレクトリィ」と呼ぶ) その中に META-INF ディレクトリィと content ディレクトリィを作る

META-INF は固定、content は任意

content ディレクトリィ (以下、「content ディレクトリィ」と呼ぶ) の名称は任意で、更にその配下に任意のディレクトリィ構造を作ることができる

本手順では content とし、すべてのリソースを直下に配置する

mimetype の作成

mimetype を作成し、EPUB ルートディレクトリィに格納する

ファイル名は mimetype 固定であり、内容は application/epub+zip のみの固定で、エンコードは必ずUS-ASCIIエンコードとなる

container.xml の作成

container.xml ファイルを作成し、META-INF ディレクトリィに格納する

ファイル名は container.xml 固定であり、変更対象は rootfile 要素の full-path 属性の値のみ

本手順では content/content.opf とする

以下、テンプレート

<?xml version='1.0' encoding='utf-8'?>
<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
  <rootfiles>
    <rootfile full-path="content/content.opf" media-type="application/oebps-package+xml" />
  </rootfiles>
</container>

本文のXHTMLの作成

本文となるXHTMLファイルを作成し、content ディレクトリィに格納する

XHTMLファイルは複数、例えば章ごとに別ファイルでも良い

EPUBはファイル名、ファイルパスの大文字小文字を区別するので、このXHTMLファイルのファイル名や、参照するファイルパス (リンクやCSSなど) の記述なども大文字小文字を区別して記述する

過去の実装との互換性の為に、拡張子はすべて小文字にした方が良いらしい

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE html>
<html xml:lang="ja" lang="ja" xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta charset="utf-8" />
    <title>タイトル</title><!-- 変更対象 -->
    <link rel="stylesheet" type="text/css" href="default.css" /><!-- 変更対象 -->
    <link rel="stylesheet" type="text/css" href="custom.css" /><!-- 変更対象 -->
  </head>
  <body>
    <!-- 変更対象 -->
  </body>
</html>

奥付のXHTMLの作成

奥付となるXHTMLファイルを作成し、content ディレクトリィに格納する

奥付はEPUBとして必須ではないが本手順では作業対象とする

以下、テンプレート

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE html>
<html xml:lang="ja" lang="ja" xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta charset="utf-8" />
    <title>タイトル - 奥付</title><!-- 変更対象 -->
    <link rel="stylesheet" type="text/css" href="default.css" /><!-- 変更対象 -->
    <link rel="stylesheet" type="text/css" href="custom.css" /><!-- 変更対象 -->
  </head>
  <body>
    <h1>タイトル</h1><!-- 変更対象 -->
    <dl class='version'>
      <dt>初版</dt>
      <dd><time datetime="yyyy-MM-dd">yyyy年MM月dd日</time></dd><!-- 変更対象 -->
      <dt>電子版 初版</dt>
      <dd><time datetime="yyyy-MM-dd">yyyy年MM月dd日</time></dd><!-- 変更対象 -->
    </dl>
    <hr/>
        <dl>
            <dt>著者</dt>
            <dd>著者名</dd><!-- 変更対象 -->
            <dt>発行</dt>
            <dd>サークル名</dd><!-- 変更対象 -->
            <dt>Web site</dt>
            <dd><address><a href='https://example.com'>example.com</a></address></dd>
            <dt>E-mail address</dt>
            <dd><address>john@example.com</address></dd>
        </dl>
        <p></p>
    <hr/>
    <p>他、注意書き等</p><!-- 変更対象 -->
  </body>
</html>

表紙絵となる画像と表紙となるXHTMLの作成

表紙絵となる画像ファイルと表紙となるXHTMLファイルを作成し、content ディレクトリィに格納する

表紙はEPUBとして必須ではないが本手順では作業対象とする

EPUBは画像ファイルとしてSVGPNGJPEG、GIFが使える

予め表紙絵の Cover.png を用意した上で表紙として以下の様なXHTMLファイルを作成する

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE html>
<html xml:lang="ja" lang="ja" xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta charset="utf-8" />
    <title>タイトル</title><!-- 変更対象 -->
  </head>
  <body>
    <div>
    <p><img alt="タイトル - 作者名等" src="cover.png" /></p><!-- 変更対象 -->
<!-- 2018-09-19 一部リーダーが object要素に対応してないようなのでimg要素によるマークアップへ変更
      <object data="Cover.png" type="image/png">
        <h1>タイトル</h1>
        <p>著者名など</p>
      </object>
-->
    </div>
  </body>
</html>

CSSの作成

XHTMLに適用するCSSファイルを作成し、content ディレクトリィに格納する

CSSEPUBとしては必須ではないが、縦書きの為に必要となる

XHTMLに直接style要素で書き込んでも良いが、本手順では独立したCSSファイルを用意する

以下、自分が使っているテンプレート

html {
  writing-mode: vertical-rl;
  -webkit-writing-mode: vertical-rl;
  -epub-writing-mode: vertical-rl;
}

body {
  text-orientation: upright;
  line-height: 180%;
}

* {
  font-size: 1.0em;
  text-align: justify;
  font-weight: inherit;
  font-style: inherit;
}

h1, h2, h3, h4, h5, h6 {
  font-weight: bold;
  margin: 3em 3em 1em 3em;
}

p {
  margin: 0;
  padding: 0;
}

hr {
  visibility : hidden;
  margin:0 1em;
}

補足説明

  • FirefoxにてXHTMLファイルとして表示した場合 writing-mode: vertical-rl; はbodyでなくhtmlにすると横スクロールバーが右側の状態で始まるのでそのようにした
  • text-orientation: upright; は内容による
  • 縦中横については考慮していない
  • p要素に text-indent:1em; を書く場合、役物が先頭に来た場合はclassで制御する
  • 他、q要素などを使い引用符を制御する場合その記述を追加する

目次の作成

目次ファイルとなるXHTMLファイルを作成し、content ディレクトリィに格納する

目次ファイルは nav 要素でマークアップし、nav 要素には名前空間 http://www.idpf.org/2007/opstype 属性で値 toc を記述する

以下、テンプレート

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE html>
<html xml:lang="ja" lang="ja" xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">
<head>
  <meta charset="utf-8" />
  <title>タイトル - 目次</title><!-- 変更対象 -->
  <link rel="stylesheet" type="text/css" href="default.css" /><!-- 変更対象 -->
</head>
<body>
  <nav epub:type="toc"><!-- 以下、nav要素の子要素全般が変更対象 -->
    <h1>タイトル - 目次</h1>
    <ol>
      <li><a href="cover.xhtml">表紙</a></li>
      <li><a href="chapter1.xhtml">第一章</a></li>
      <li><a href="chapter2.xhtml">第二章</a></li>
      <li><a href="chapter3.xhtml">第三章</a></li>
      <li><a href="colophon.xhtml">奥付</a></li>
    </ol>
  </nav>
</body>
</html>

XHTMLの確認

Nu Html CheckerXHTMLファイルの確認を行う

XML宣言、目次の http://www.idpf.org/2007/ops 名前空間の宣言とその名前空間type 属性以外でError、warningが出たら直す

content.opf の作成

content.opf を作成し、content ディレクトリィに格納する

metadata 要素

metadata 要素には書籍情報を記述する

manifest 要素

manifest 要素には、content ディレクトリィにあるcontent.opf以外のすべてのファイルを item 要素としてマークアップする

item 要素

item 要素には、id 属性、href 属性を記述する

href 属性の値はcontent ディレクトリィ内の相対パスとする

表紙画像には properties 属性で cover-image を記述する

目次には properties 属性で nav を記述する

spine 要素

spine 要素には、itemref 要素としてEPUB内で独立して内容となるファイルを昇順で記述する

ここでいう独立して内容となるとは、例えばXHTML内で参照される画像やスタイルシートを含まないことを意味する

本手順で作成するEPUBはページ送りが右から左であるため、spine 要素にpage-progression-direction 属性を記述し値を rtl とする

itemref 要素

itemref 要素には idref 属性を記述する

以下、テンプレート

<?xml version="1.0" encoding="utf-8"?>
<package unique-identifier="BookId" version="3.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns="http://www.idpf.org/2007/opf">
  <metadata>
    <dc:title>タイトル</dc:title><!-- 変更対象 -->
    <dc:creator>作者名</dc:creator><!-- 変更対象 -->
    <dc:language>ja-JP</dc:language>
    <dc:identifier id="BookId">tag:example.com,yyyy-MM-dd:BookId</dc:identifier><!-- 変更対象 -->
    <meta property="dcterms:modified">yyyy-MM-ddThh:mm:ddZ</meta><!-- 変更対象 -->
  </metadata>
  <manifest><!-- 以下、manifest 要素の子要素全般が変更対象 -->
    <item id="cover" href="cover.xhtml" media-type="application/xhtml+xml" />
    <item id="navigation" href="navigation.xhtml" media-type="application/xhtml+xml" properties="nav" />
    <item id="chapter1" href="chapter1.xhtml" media-type="application/xhtml+xml" />
    <item id="chapter2" href="chapter2.xhtml" media-type="application/xhtml+xml" />
    <item id="chapter3" href="chapter3.xhtml" media-type="application/xhtml+xml" />
    <item id="colophon" href="colophon.xhtml" media-type="application/xhtml+xml" />
    <item id="defaultStlye" href="default.css" media-type="text/css" />
    <item id="navigationStyle" href="navigation.css" media-type="text/css" />
    <item id="chapterStyle" href="chapter.css" media-type="text/css" />
    <item id="colophonStlye" href="colophon.css" media-type="text/css" />
    <item id="coverImage" href="cover.png" media-type="image/png" properties="cover-image" />
  </manifest>
  <spine page-progression-direction="rtl"><!-- spine 要素の子要素全般が変更対象 -->
    <itemref idref="cover" />
    <itemref idref="navigation" />
    <itemref idref="chapter1" />
    <itemref idref="chapter2" />
    <itemref idref="chapter3" />
    <itemref idref="colophon" />
  </spine>
</package>

ZIP化する

EPUB ルートディレクトリィをZIP化し、拡張子を .epub とする

互換性の問題でEPUBの拡張子はすべて小文字で .epub とするのが良いらしい

ZIPファイル内には先頭に非圧縮で mimetype ファイルを配置した上でそれ以外のファイルを格納する

本手順ではbashにて実行する

  1. EPUB ルートディレクトリィへ移動する
  2. mimetypeのみを非圧縮でZIP化
    zip -0Xq Document.epub mimetype
  3. 他のファイルをZIP化
    zip -Xr9Dq SampleEpub.epub *

コマンドのオプション

-# (-0 ... -9)
0が非圧縮、9が最大圧縮
-X
no extra
余計なファイル属性を保存しない
-q
quiet
サイレント実行
-r
recurse paths
ディレクトリ構造を再帰的に取得し対象とする
-D
no dir entries
ディレクトリのzipアーカイブディレクトリィエントリを作成しない

EPUB Validatorで確認する

EPUB Validator (beta) を使って生成したEPUBファイルを確認する

Error、Warningが出たら直す

同人小説を初めてEPUBにした時の覚書

この記事は、自分の試行錯誤の垂れ流しなので、いつも以上に突っ込み歓迎です

過去発行していた同人小説のEPUB版を作ることにしました

EPUBを選んだ理由は縦書きにしたい固定レイアウトにする必要はない内容なのでリフロー版にしたいだったので、EPUBでも3.0.1か3.1が対象になります

その上で、今回参照した本がEPUB3を対象としており、これに従ってEPUBを作ったらValidatorからEPUB3.0.1と認定されたので下記は3.0.1 (としてValidatorを通過できるファイル) を作る作業記録になります

仕様 (邦訳) とか参考文献とか資料とかツールとか

サンプルEPUBを作ってみる

EPUBファイルは特定のディレクトリィ構造、ファイルを持つZIPファイルです

今回作るSample EPUBの構成は以下の通りです (下記の ContentSampleEpubNavigation は任意の名称)

mimetype
META-INF/container.xml
Content/SampleEpub.opf
Content/SampleEpub.xhtml
Content/Navigation.xhtml

mimetype

4.3 OCF ZIP Container Media Type Identification - EPUB Open Container Format (OCF) 3.1

mimetypeファイルは application/epub+zip のみを内容物として持つファイルで文字コードはUS-ASCIIです

META-INF/container.xml

META-INF/container.xml は以下の通りです

フォルダ名の META-INF ファイル名の container.xml 共に名称は固定です

<?xml version='1.0' encoding='utf-8'?>
<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
  <rootfiles>
    <rootfile full-path="Content/SampleEpub.opf" media-type="application/oebps-package+xml" />
  </rootfiles>
</container>

rootfile 要素の full-path 属性の値は、実際のopfファイルの相対パスになり、それ以外の内容は固定になります

Content/SampleEpub.opf

Content/SampleEpub.opf (フォルダ名、ファイル名は container.xml で指定した任意の物) は以下の通りです

フォルダ名の Content ファイル名の SampleEpub は任意の名称になりますが、拡張子の '.opf' は多分固定です (あるいは変えない方が無難です)

<?xml version='1.0' encoding='utf-8'?>
<package unique-identifier="BookId" version="3.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns="http://www.idpf.org/2007/opf">
  <metadata>
    <dc:title>Sample Epub</dc:title>
    <dc:language>ja</dc:language>
    <dc:identifier id="BookId">tag:example.com,2018-09-11:BookId/Sample Epub</dc:identifier>
    <meta property="dcterms:modified">2018-09-11T00:00:00Z</meta>
  </metadata>
  <manifest>
    <item id="Navigation" href="Navigation.xhtml" media-type="application/xhtml+xml" properties="nav" />
    <item id="SampleEpub" href="SampleEpub.xhtml" media-type="application/xhtml+xml" />
  </manifest>
  <spine>
    <itemref idref="Navigation" />
    <itemref idref="SampleEpub" />
  </spine>
</package>

opfファイルはXMLファイルで、document要素は package 要素となります

package 要素の unique-identifier 属性の値は任意のIDとなる値です

package 要素の子要素は metadatamanifestspine の3要素となり、それぞれについて説明します

metadata 要素

metadata 要素は要素名の通りEPUBファイルのメタデータ (書誌情報) を格納する要素です

dc名前空間の子要素として最低限 titlelanguageidentifier を記述します

title 要素は文字通りの本のタイトルを記述し、language 要素はIETF言語タグ (RFC 4646 および RFC 4647) で日本語の場合は ja または ja-JP を記述します

identifier要素は id 属性に document 要素の package 要素の unique-identifier 属性の値と同一の値を設定し、子要素としてIDREF (XML)のTextNodeを記述します

この identifier 要素の内容となる IDREF は、 property 属性に dcterms:modified を持つ meta 要素の日付と合わせて同一の書籍の同一性と異なる版の判別に使われます

manifest 要素

manifest 要素には子要素として順不同でEPUB内に格納しているコンテンツを item 要素として記載します

XHTML内から参照される画像や直接コンテンツとはならないstyle sheetなどもEPUBを構成するファイルは item 要素となります

item 要素

item 要素には id 属性、href 属性、media-type 属性を記載します

id属性は任意のid、href属性にはopfファイルから見た相対パスmedia-typeにはMINEの値を記載します

なお参照するファイルがXHTMLの場合、拡張子は.xhtmlMIMEapplication/xhtml+xmlとします

また、カバー絵となる画像を参照する item 要素には properties 属性でcover-image を設定し、目次となるXHTMLを参照する itme要素には同じくproperties 属性で nav" を記述します

spine 要素

spine 要素には子要素としてEPUBの内容を昇順で itemref 要素として記述します

itemref 要素

itemref要素にはidref属性で各リソースのIDを記述します

このidは manifest 要素の子要素の item 要素の id 属性の値になります

目次を記述する

XHTMLで目次を記述します

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE html>
<html xml:lang="ja" lang="ja" xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">
  <head>
    <meta charset="utf-8" />
    <title>Sample Epub</title>
  </head>
  <body>
    <nav epub:type="toc">
      <h1>Sample Epub - 目次</h1>
      <ol>
        <li><a href="Sample Epub.xhtml">Sample Epub</a></li>
      </ol>
    </nav>
  </body>
</html>

EPUBの目次は opf ファイルの item 要素には properties 属性で properties 属性で nav" を記述した上で、XHTML文書内ではnav要素を使ってマークアップし、更に nav 要素には http://www.idpf.org/2007/ops 名前空間type 属性として toc を記述します

ZIP化してみる

Windows上でEPUBファイルとなるZIPファイルを作ろうとしたがどうしてもうまくいかなかったので、今回は EPUB で電子書籍を作成するEPUB ファイルを ZIP アーカイブとしてバンドルする を参考にbashでコマンドを叩くことにしました

以下、bashでZIPファイルを作ったときの作業

  1. 身近なbashWindows 10上のWindows Subsystem for LinuxUbuntu 18.04のbashだったのでそれを起動
  2. WSLにZIPがインストールされていなかったので $ sudo apt install zip unzip でZIPをインストール
  3. Windows上のドライブはrootの mnt ディレクトリィにマウントされているので $ cd /mnt/c/users/(以下略) でEpupファイルを作りたいディレクトリィに移動
  4. 最初に mimetype ファイルを非圧縮でzipに追加するために $ zip -0Xq SampleEpub.epub mimetype を実行
  5. 続いてmimetype以外のファイルをZIPに追加するために$ zip -Xr9Dq SampleEpub.epub *

チェッカーで確認してみる

EPUB Validator (beta) を使ってチェックしてみます

ここでエラーやワーニングが出たらGoogle翻訳先生に聞きながら直します

色々弄ったら、3.0.1 のファイルとして合格しました

右綴じ、縦書きのEPUBファイルにする

右綴じのEPUBの場合、opfファイルのspine要素に page-progression-direction 属性として rtl を記述します

縦書きの場合、各XHTMLファイルにCSSwriting-mode: vertical-rl; を適用することで縦書きになります

なお、筆者が不勉強のため各ビュワーの対応状況などについて把握していないのですが、-webkit- プレフィックス-epub- プレフィックスを付けた writing-mode プロパティも併せて記述した方が良いようです (-webkit- の方は問題がないことを確認したら外したい)

writing-mode: vertical-rl;
-webkit-writing-mode: vertical-rl;
-epub-writing-mode: vertical-rl;


現時点ではざっくりこんな感じで