2012年2月2日木曜日

EPUBファイルの作り方

EPUB作りたいって人がいたので少しJavaで実装してみた。

EPUBとは
EPUBとは電子書籍の形式で最近3.0が仕様確定したのは 知ってたんだけど、内容自体はZIP形式で少し特徴があり 単純にZIPしてはいけないので注意が必要。
EPUBの構成
・mimetype (非圧縮ファイル) ・META-INF/container.xml (構成ファイルを指定) ・EPUB(任意)/****.opf (構成ファイル) という構成。 opfファイルの中身やその後の構成についてはEPUBの仕様説明になるので 一応ここから割愛。
mimetypeについて
ファイルの内容自体は固定で 「application/epub+zip」を書き込むファイルを作ってやる。 特徴なのは「非圧縮で先頭」である必要があるので ZipOutputStreamを開始して最初のエントリーを以下のように非圧縮にしてやれば良い。
        String mime = "application/epub+zip";
        ZipEntry entry = new ZipEntry("mimetype");
        byte[] mimeData;
  try {
   mimeData = mime.getBytes("UTF-8");
  } catch (UnsupportedEncodingException e1) {
   throw new RuntimeException(e1);
  }
        entry.setSize(mimeData.length);
        entry.setCompressedSize(mimeData.length);
        entry.setCrc(0x2CAB616F);
        entry.setMethod(ZipEntry.STORED);

        // 出力先 Entry を設定する。
        try {
   zos.putNextEntry(entry);
         zos.write(mimeData);
         zos.closeEntry();
  } catch (IOException e) {
   e.printStackTrace();
  }

META-INF/container.xmlについて
これは単純に構成ファイルの位置指定なので
    private String OPF_PATH = "EPUB";
    private String OPF_FILE = "book.opf";

 private void createContainerXml() {
     String xml = "<?xml version=\"1.0\"?>";
     xml += "<container version=\"1.0\" xmlns=\"urn:oasis:names:tc:opendocument:xmlns:container\">";
     xml += "<rootfiles>";

     String fileName = OPF_PATH + "/" + OPF_FILE;
     xml += "<rootfile full-path=\"" + fileName + "\" media-type=\"application/oebps-package+xml\"/>";
     xml += "</rootfiles>";
     xml += "</container>";

     try {
      ZipEntry entry = new ZipEntry("META-INF/container.xml");
   put(entry,xml.getBytes("UTF-8"));
  } catch (UnsupportedEncodingException e) {
   throw new RuntimeException(e);
  }
 }

みたいな感じで固定の値を設定してあげる。 put()関数は単純にZipOutputStreamにエントリーしている関数です。
opfファイルについて
META-INF/container.xmlファイルに指定したopfファイルに EPUBが構成するようなファイルを指定していくらしい。 EPUBのサンプルとしてGoogle Codeにおいてあったのでこちらで実験した。
ZIPする時の注意点
実際の時とは違うんだけど、Windowsのファイルシステムでやっていると 「¥」でパスを設定してしまい、AdobeのViewerはそれを認識できない(EPUBの仕様?)ので それを変換する必要がある。
     entryName = entryName.replaceAll("\\\\", "/");
おなじみのですね><v それと将来的にはメモリ上でやるのでこの失敗はないと思うんだけど、 ファイルシステムを検索してEntryを作っていると 「/META-INF/container.xml」 とEntryする事もあり、ZIP自体はこれでもOKなんだけど、 「META-INF/container.xml」 としてやらないと読み込んでくれなかった。 ※これもViewerの仕様がEPUBの仕様かは不明。 一応これでサンプルのファイルを利用してZIPで固めたらOKだった。
サービス化を考えている友人へ
固めるところは技術的に見れば簡単なんだけど、 実際は「opfファイル」をサービスとして提供しなければ行けないところで 本を作っている人がこれを書きこむってのはサービス上はありえないわけで、 まぁこんな圧縮程度で止まっている場合ではないって事です。

1 件のコメント:

Kazuomatz さんのコメント...

サービス化を考えている友人の友人ですが、Railsで同じ物作り始めました。