epub の画像ファイル名を連番に修正する

マンガのepubのリーダーアプリとしてNeeViewを使っている。 これはepubがzipファイルであることを利用して、中の画像ファイルを表示させることで簡易的にepubリーダーになる。

ところが、これは画像ファイル名が連番であることを暗に前提としている。というのも、連番になっていないepubではページの順番が狂うのだ。

ということで、epubの画像ファイル名を連番に変換するrubyスクリプトを書いた。あまり綺麗でないが、まあ使えるだろう。

使い方

  1. epubファイルを a.zipに名前を変更し、フォルダ名 a に展開する。
  2. opfファイルがあるフォルダで、このスクリプトを実行する。OEBPS か OPS のようなフォルダ内にある。
  3. a より上位のフォルダでMakefileを実行してepubを生成する。

epbuのフォルダ構成

epbuのフォルダ構成はたいて以下のような二つのパターンになっている:

パターンA

a/
├── META-INF/
├── OPS/
├── js/
├── mimetype
└── rights.xml

パターンB

a/
├── mimetype
├── META-INF/
└── OEBPS/

Ruby スクリプト

#!/usr/bin/env ruby
require 'pathname'

dry_run = false
ARGV.each{|opf|
  # jpg, xhtmlのリストを生成
  jpg_fileNameOldNew = Hash.new
  xhtml_list         = Array.new
  File.open(opf){|f|
    cnt = 0
    f.each_line{|line|
      if /"([^"]+\.jpg)"/i =~ line
        fileNameOld1 = $1
        filePathOld = Pathname(fileNameOld1)
        fileNameNew = sprintf("image_%06d.jpg", cnt)
        filePathNew = Pathname(filePathOld.parent + fileNameNew)
        jpg_fileNameOldNew[filePathOld.to_s] = filePathNew.to_s
        cnt += 1
      elsif /href="([^"]+\.xhtml)"/i =~ line
#        p $1
        xhtml_list.push($1)
      end
    }
  }
  p jpg_fileNameOldNew # for debug
  p xhtml_list         # for debug
  opf_old = ""
  opf_new = ""
  File.open(opf){|f|
    opf_new = f.read
    opf_old = opf_new
    jpg_fileNameOldNew.each_key{|key|
      if /(#{key})/ =~ opf_new
        p $1
        p jpg_fileNameOldNew[key]
        opf_new = opf_new.gsub(/#{key}/, jpg_fileNameOldNew[key])
      end
    }
  }
  # オリジナルのopfをrenameして保存
  # 書き換えたopfを保存
  p opf_old # for debug
  p opf_new # for debug
  if !dry_run
#    File.rename(opf, opf + ".orig")
    File.open(opf, "w"){|f_new|
      f_new.puts(opf_new)
    }
  end
  # xhtmlの書き換え
  xhtml_list.each{|xhtml|
    contents_old = ""
    contents_new = ""
    File.open(xhtml){|f|
      p f
      contents_new = f.read
      contents_old = contents_new # for debug
      jpg_fileNameOldNew.each_key{|key|
        if /(#{key})/ =~ contents_new
          p $1
          p jpg_fileNameOldNew[key]
          contents_new = contents_new.gsub(/#{key}/, jpg_fileNameOldNew[key])
        end
      }
    }
    # オリジナルのxhtmlをrenameして保存
    # 書き換えたxhtmlを保存
    p contents_old # for debug
    p contents_new # for debug
    if !dry_run
#      File.rename(xhtml, xhtml + ".orig")
      File.open(xhtml, "w") {|f_new|
        f_new.puts(contents_new)
      }
    end
  }
  jpg_fileNameOldNew.each_key{|key|
    # jpgファイルをリネームする
    orig_name = key
    new_name  = jpg_fileNameOldNew[key]
    if !dry_run
      File.rename(orig_name, new_name)      
    end
  }
 }

Makefile

この Makefile は、a/ 内の構成を見て、自動的に対象ファイルを切り替える。

EPUB_NAME = book.epub
SOURCE_DIR = a

# 検出対象ファイル・ディレクトリ
PATTERN_A = META-INF OPS js rights.xml
PATTERN_B = META-INF OEBPS

# mimetype はどちらでも共通
MIMETYPE_FILE = $(SOURCE_DIR)/mimetype

# デフォルトターゲット
all: $(EPUB_NAME)

# 条件付きでコンテンツを選択
$(EPUB_NAME): $(MIMETYPE_FILE)
	@rm -f $(EPUB_NAME)
	@echo "Detecting EPUB structure..."
	@if [ -d "$(SOURCE_DIR)/OPS" ] && [ -d "$(SOURCE_DIR)/js" ] && [ -f "$(SOURCE_DIR)/rights.xml" ]; then \
		echo "Using pattern A (OPS/js/rights.xml)"; \
		cd $(SOURCE_DIR) && zip -X0 ../$(EPUB_NAME) mimetype && \
		zip -Xr9D ../$(EPUB_NAME) $(PATTERN_A); \
	elif [ -d "$(SOURCE_DIR)/OEBPS" ]; then \
		echo "Using pattern B (OEBPS only)"; \
		cd $(SOURCE_DIR) && zip -X0 ../$(EPUB_NAME) mimetype && \
		zip -Xr9D ../$(EPUB_NAME) $(PATTERN_B); \
	else \
		echo "Error: Could not determine valid EPUB structure in '$(SOURCE_DIR)'."; \
		exit 1; \
	fi
	@echo "EPUB created: $(EPUB_NAME)"

clean:
	rm -f $(EPUB_NAME)


使用方法

  1. この Makefile を a/ の1つ上の階層に配置する。
  2. ターミナルでその階層へ移動して:
    make
    

おまけ

Windows上のepubリーダーは、実は紀伊国屋のKinoppyがおすすめだ。 Knoppyはテキストベースのepubの縦書きに対応しており、とても使いやすい。