Search in sources :

Example 1 with ChapterLineInfo

use of com.github.hmdev.info.ChapterLineInfo in project AozoraEpub3 by hmdev.

the class JConfirmDialog method convert.

/** 変換実行 */
void convert() {
    if (jTextTitle.getText().replaceFirst("^[ | ]+", "").replaceFirst("[ | ]+$", "").length() == 0) {
        JOptionPane.showMessageDialog(this, "タイトルを設定してください。");
    } else {
        this.canceled = false;
        this.setVisible(false);
        //挿絵が選択されていたらファイル名はnull
        if (bookInfo.coverImageIndex > -1)
            bookInfo.coverFileName = null;
        //目次設定
        if (!this.bookInfo.isImageOnly() && this.tocDataModel != null) {
            //編集中なら確定
            if (this.jTableToc.isEditing())
                this.jTableToc.getCellEditor().stopCellEditing();
            int cnt = this.tocDataModel.getRowCount();
            for (int row = 0; row < cnt; row++) {
                int lineNum = this.tocDataModel.getLineNum(row) - 1;
                ChapterLineInfo chapterLineInfo = bookInfo.getChapterLineInfo(lineNum);
                if (chapterLineInfo != null) {
                    if (!this.tocDataModel.isSelected(row)) {
                        this.bookInfo.removeChapterLineInfo(chapterLineInfo.lineNum);
                    } else {
                        chapterLineInfo.setChapterName(this.tocDataModel.getTocName(row));
                    }
                }
            }
        }
        //表紙情報保存
        bookInfo.coverEditInfo = this.jCoverImagePanel.getCoverEditInfo();
    }
}
Also used : ChapterLineInfo(com.github.hmdev.info.ChapterLineInfo) Point(java.awt.Point)

Example 2 with ChapterLineInfo

use of com.github.hmdev.info.ChapterLineInfo in project AozoraEpub3 by hmdev.

the class JConfirmDialog method showDialog.

/** 確認ダイアログを表示
	 * @param location ダイアログ表示位置 */
public void showDialog(File srcFile, String dstPath, String title, String creator, int titleTypeIndex, boolean pubFirst, BookInfo bookInfo, ImageInfoReader imageInfoReader, Point location, int coverW, int coverH) {
    //zip内テキストファイル名も表示
    String srcFileName = srcFile.getName();
    if (bookInfo.textEntryName != null)
        srcFileName += " : " + bookInfo.textEntryName.substring(bookInfo.textEntryName.lastIndexOf('/') + 1);
    this.jTextSrcFileName.setText(srcFileName);
    this.jTextSrcFileName.setToolTipText(srcFileName);
    //this.jTextSrcFileName.setCaretPosition(0);
    this.jTextDstFileName.setText(dstPath);
    this.jTextDstFileName.setToolTipText(dstPath);
    //this.jTextDstFileName.setCaretPosition(0);
    //メタデータ設定
    this.jTextTitle.setText(title);
    this.jTextTitleAs.setText(bookInfo.titleAs == null ? "" : bookInfo.titleAs);
    this.jTextCreator.setText(creator);
    this.jTextCreatorAs.setText(bookInfo.creatorAs == null ? "" : bookInfo.creatorAs);
    this.jTextPublisher.setText(bookInfo.publisher == null ? "" : bookInfo.publisher);
    //this.jCheckReplaceCover.setSelected(false);
    //変更前確認設定用
    this.jCheckConfirm2.setSelected(true);
    this.jComboTitle.setSelectedIndex(titleTypeIndex);
    this.jCheckPubFirst.setSelected(pubFirst);
    this.jComboTitle.setEnabled(!bookInfo.isImageOnly());
    this.jButtonTitle.setEnabled(!bookInfo.isImageOnly());
    //プレビュー読み込み
    try {
        if (bookInfo.coverImageIndex >= 0 && bookInfo.coverImageIndex < imageInfoReader.countImageFileNames()) {
            bookInfo.coverImage = imageInfoReader.getImage(bookInfo.coverImageIndex);
        }
        if (bookInfo.coverImage == null) {
            if (bookInfo.coverFileName == null) {
                String srcPath = srcFile.getParent();
                File coverFile = new File(srcPath + "/cover.png");
                if (!coverFile.exists())
                    coverFile = new File(srcPath + "/cover.jpg");
                if (!coverFile.exists())
                    coverFile = new File(srcPath + "/cover.jpeg");
                if (coverFile.exists())
                    bookInfo.coverFileName = coverFile.getAbsolutePath();
            }
            if (bookInfo.coverFileName != null) {
                bookInfo.loadCoverImage(bookInfo.coverFileName);
                bookInfo.coverImageIndex = -1;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    //フラグ初期化
    this.canceled = false;
    this.skipped = false;
    this.coverW = coverW;
    this.coverH = coverH;
    this.bookInfo = bookInfo;
    this.imageInfoReader = imageInfoReader;
    //全選択チェック
    jCheckChapterAll.setSelected(true);
    //目次に無いものはdisabled
    jCheckChapterH.setEnabled(false);
    jCheckChapterH1.setEnabled(false);
    jCheckChapterH2.setEnabled(false);
    jCheckChapterH3.setEnabled(false);
    jCheckChapterName.setEnabled(false);
    jCheckChapterNum.setEnabled(false);
    jCheckChapterPattern.setEnabled(false);
    jCheckChapterSection.setEnabled(false);
    //目次設定
    if (bookInfo.isImageOnly()) {
        this.tocDataModel = null;
        this.jTableToc.setVisible(false);
        this.jScrollToc.setVisible(false);
    } else {
        Vector<ChapterLineInfo> vecChapterLineInfo = bookInfo.getChapterLineInfoList();
        this.tocDataModel = this.jTableToc.getModel();
        this.tocDataModel.setRowCount(0);
        for (ChapterLineInfo chapterLineInfo : vecChapterLineInfo) {
            if (chapterLineInfo.pageBreakChapter)
                jCheckChapterSection.setEnabled(true);
            switch(chapterLineInfo.type) {
                case ChapterLineInfo.TYPE_CHUKI_H:
                    jCheckChapterH.setEnabled(true);
                    break;
                case ChapterLineInfo.TYPE_CHUKI_H1:
                    jCheckChapterH1.setEnabled(true);
                    break;
                case ChapterLineInfo.TYPE_CHUKI_H2:
                    jCheckChapterH2.setEnabled(true);
                    break;
                case ChapterLineInfo.TYPE_CHUKI_H3:
                    jCheckChapterH3.setEnabled(true);
                    break;
                case ChapterLineInfo.TYPE_CHAPTER_NAME:
                    jCheckChapterName.setEnabled(true);
                    break;
                case ChapterLineInfo.TYPE_CHAPTER_NUM:
                    jCheckChapterNum.setEnabled(true);
                    break;
                case ChapterLineInfo.TYPE_PATTERN:
                    jCheckChapterPattern.setEnabled(true);
                    break;
            }
            //行の値設定
            tocDataModel.addRow(new Object[] { true, chapterLineInfo.pageBreakChapter ? "改" : "", chapterLineInfo.getTypeId(), chapterLineInfo.lineNum + 1, chapterLineInfo.getChapterName() });
        }
        this.jTableToc.getTableHeader().setPreferredSize(new Dimension(100, 20));
        this.jTableToc.setVisible(true);
        this.jScrollToc.setVisible(true);
        this.jScrollToc.getVerticalScrollBar().setValue(0);
    }
    if (this.canceled)
        return;
    //サイズ調整
    this.setCoverPaneSize(1);
    //表示画像設定
    this.jCoverImagePanel.setBookInfo(bookInfo);
    this.jButtonScale.setSelected(false);
    if (bookInfo.coverEditInfo == null)
        this.jCoverImagePanel.setFitType(JCoverImagePanel.FIT_ALL, true);
    this.checkPreviewControlEnabled();
    this.jCheckReplaceCover.setVisible(bookInfo.insertCoverPage);
    //本情報設定ダイアログ表示
    if (!this.firstShown)
        this.setLocation(location.x + 100, location.y + 20);
    this.firstShown = true;
    this.setVisible(true);
}
Also used : ChapterLineInfo(com.github.hmdev.info.ChapterLineInfo) Dimension(java.awt.Dimension) File(java.io.File) MalformedURLException(java.net.MalformedURLException) IOException(java.io.IOException)

Example 3 with ChapterLineInfo

use of com.github.hmdev.info.ChapterLineInfo in project AozoraEpub3 by hmdev.

the class AozoraEpub3Converter method getBookInfo.

/** タイトルと著作者を取得. 行番号も保存して出力時に変換出力
	 * 章洗濯用に見出しの行もここで取得
	 * @param src 青空テキストファイルのReader
	 * @param imageInfoReader テキスト内の画像ファイル名を格納して返却
	 * @param titleType 表題種別
	 * @param coverFileName 表紙ファイル名 nullなら表紙無し ""は先頭ファイル "*"は同じファイル名 */
public BookInfo getBookInfo(File srcFile, BufferedReader src, ImageInfoReader imageInfoReader, TitleType titleType, boolean pubFirst) throws Exception {
    try {
        BookInfo bookInfo = new BookInfo(srcFile);
        String line;
        this.lineNum = -1;
        //前の行のバッファ [1行前, 2行前]
        String[] preLines = new String[] { null, null };
        //コメントブロック内
        boolean inComment = false;
        //コメントが始まったらtrue
        boolean firstCommentStarted = false;
        //最初のコメント開始行
        int firstCommentLineNum = -1;
        //先頭行
        String[] firstLines = new String[10];
        //先頭行の開始行番号
        int firstLineStart = -1;
        //タイトルページ開始行 画像等がなければ-1 タイトルなしは-2
        //int preTitlePageBreak = titleType==TitleType.NONE ? -2 : -1;
        //コメント内の行数
        int commentLineNum = 0;
        //コメント開始行
        int commentLineStart = -1;
        //直線の空行
        int lastEmptyLine = -1;
        //目次用見出し自動抽出
        boolean autoChapter = this.autoChapterName || this.autoChapterNumTitle || this.autoChapterNumOnly || this.autoChapterNumParen || this.autoChapterNumParenTitle || this.chapterPattern != null;
        //改ページ後の目次を追加するならtrue
        boolean addSectionChapter = true;
        //見出し注記の後の文字を追加
        boolean addChapterName = false;
        //見出しの次の行を繋げるときに見出しの次の行番号を設定
        int addNextChapterName = -1;
        //ブロック見出し注記、次の行を繋げる場合に設定
        ChapterLineInfo preChapterLineInfo = null;
        //最後まで回す
        while ((line = src.readLine()) != null) {
            this.lineNum++;
            //見出し等の取得のため前方参照注記は変換 外字文字は置換
            line = CharUtils.removeSpace(this.replaceChukiSufTag(this.convertGaijiChuki(line, true, false)));
            //注記と画像のチェックなので先にルビ除去
            String noRubyLine = CharUtils.removeRuby(line);
            //コメント除外 50文字以上をコメントにする
            if (noRubyLine.startsWith("--------------------------------")) {
                if (!noRubyLine.startsWith("--------------------------------------------------")) {
                    LogAppender.warn(lineNum, "コメント行の文字数が足りません");
                } else {
                    if (firstCommentLineNum == -1)
                        firstCommentLineNum = this.lineNum;
                    //コメントブロックに入ったらタイトル著者終了
                    firstCommentStarted = true;
                    if (inComment) {
                        //コメント行終了
                        if (commentLineNum > 20)
                            LogAppender.warn(lineNum, "コメントが " + commentLineNum + " 行 (" + (commentLineStart + 1) + ") -");
                        commentLineNum = 0;
                        inComment = false;
                        continue;
                    } else {
                        if (lineNum > 10 && !(commentPrint && commentConvert))
                            LogAppender.warn(lineNum, "コメント開始行が10行目以降にあります");
                        //コメント行開始
                        commentLineStart = this.lineNum;
                        inComment = true;
                        continue;
                    }
                }
                if (inComment)
                    commentLineNum++;
            }
            //空行チェック
            if (noRubyLine.equals("") || noRubyLine.equals(" ") || noRubyLine.equals(" ")) {
                lastEmptyLine = lineNum;
                //空行なので次の行へ
                continue;
            }
            if (inComment && !this.commentPrint)
                continue;
            //2行前が改ページと画像の行かをチェックして行番号をbookInfoに保存
            if (!noIllust)
                this.checkImageOnly(bookInfo, preLines, noRubyLine, this.lineNum);
            //見出しのChapter追加
            if (addChapterName) {
                if (//前の見出しがなければ中止
                preChapterLineInfo == null)
                    //前の見出しがなければ中止
                    addChapterName = false;
                else {
                    String name = this.getChapterName(noRubyLine);
                    //字下げ注記等は飛ばして次の行を見る
                    if (name.length() > 0) {
                        preChapterLineInfo.setChapterName(name);
                        preChapterLineInfo.lineNum = lineNum;
                        addChapterName = false;
                        //次の行を繋げる設定
                        if (this.useNextLineChapterName)
                            addNextChapterName = lineNum + 1;
                        //改ページ後のChapter出力を抑止
                        addSectionChapter = false;
                    }
                    //必ず文字が入る
                    preChapterLineInfo = null;
                }
            }
            //画像のファイル名の順にimageInfoReaderにファイル名を追加
            Matcher m = chukiPattern.matcher(noRubyLine);
            while (m.find()) {
                String chukiTag = m.group();
                String chukiName = chukiTag.substring(2, chukiTag.length() - 1);
                if (chukiFlagPageBreak.contains(chukiName)) {
                    //改ページ注記ならフラグON
                    addSectionChapter = true;
                } else if (chapterChukiMap.containsKey(chukiName)) {
                    //見出し注記
                    //注記の後に文字がなければブロックなので次の行 (次の行にブロック注記はこない?)
                    int chapterType = chapterChukiMap.get(chukiName);
                    if (noRubyLine.length() == m.start() + chukiTag.length()) {
                        preChapterLineInfo = new ChapterLineInfo(lineNum + 1, chapterType, addSectionChapter, ChapterLineInfo.getLevel(chapterType), lastEmptyLine == lineNum - 1);
                        bookInfo.addChapterLineInfo(preChapterLineInfo);
                        //次の行を見出しとして利用
                        addChapterName = true;
                        addNextChapterName = -1;
                    } else {
                        bookInfo.addChapterLineInfo(new ChapterLineInfo(lineNum, chapterType, addSectionChapter, ChapterLineInfo.getLevel(chapterType), lastEmptyLine == lineNum - 1, this.getChapterName(noRubyLine.substring(m.end()))));
                        //次の行を連結
                        if (this.useNextLineChapterName)
                            addNextChapterName = lineNum + 1;
                        //次の行を見出しとして利用しない
                        addChapterName = false;
                    }
                    //改ページ後のChapter出力を抑止
                    addSectionChapter = false;
                }
                String lowerChukiTag = chukiTag.toLowerCase();
                int imageStartIdx = chukiTag.lastIndexOf('(');
                if (imageStartIdx > -1) {
                    int imageEndIdx = chukiTag.indexOf(")", imageStartIdx);
                    int imageDotIdx = chukiTag.indexOf('.', imageStartIdx);
                    //訓点送り仮名チェック #の次が(で.を含まない
                    if (imageDotIdx > -1 && imageDotIdx < imageEndIdx) {
                        //画像ファイル名を取得し画像情報を格納
                        String imageFileName = this.getImageChukiFileName(chukiTag, imageStartIdx);
                        if (imageFileName != null) {
                            imageInfoReader.addImageFileName(imageFileName);
                            if (bookInfo.firstImageLineNum == -1) {
                                //小さい画像は無視
                                ImageInfo imageInfo = imageInfoReader.getImageInfo(imageInfoReader.correctExt(imageFileName));
                                if (imageInfo != null && imageInfo.getWidth() > 64 && imageInfo.getHeight() > 64) {
                                    bookInfo.firstImageLineNum = lineNum;
                                    bookInfo.firstImageIdx = imageInfoReader.countImageFileNames() - 1;
                                }
                            }
                        }
                    }
                } else if (lowerChukiTag.startsWith("<img")) {
                    //src=の値抽出
                    String imageFileName = this.getTagAttr(chukiTag, "src");
                    if (imageFileName != null) {
                        //画像がなければそのまま追加
                        imageInfoReader.addImageFileName(imageFileName);
                        if (bookInfo.firstImageLineNum == -1) {
                            //小さい画像は無視
                            ImageInfo imageInfo = imageInfoReader.getImageInfo(imageInfoReader.correctExt(imageFileName));
                            if (imageInfo != null && imageInfo.getWidth() > 64 && imageInfo.getHeight() > 64) {
                                bookInfo.firstImageLineNum = lineNum;
                                bookInfo.firstImageIdx = imageInfoReader.countImageFileNames() - 1;
                            }
                        }
                    }
                }
            }
            //TODO パターンと目次レベルは設定可能にする 空行指定の場合はpreLines利用
            if (autoChapter && bookInfo.getChapterLevel(lineNum) == 0) {
                //文字列から注記と前の空白を除去
                String noChukiLine = CharUtils.removeSpace(CharUtils.removeTag(noRubyLine));
                //その他パターン
                if (this.chapterPattern != null) {
                    if (this.chapterPattern.matcher(noChukiLine).find()) {
                        bookInfo.addChapterLineInfo(new ChapterLineInfo(lineNum, ChapterLineInfo.TYPE_PATTERN, addSectionChapter, ChapterLineInfo.getLevel(ChapterLineInfo.TYPE_PATTERN), lastEmptyLine == lineNum - 1, this.getChapterName(noRubyLine)));
                        //次の行を連結
                        if (this.useNextLineChapterName)
                            addNextChapterName = lineNum + 1;
                        //改ページ後のChapter出力を抑止
                        addSectionChapter = false;
                    }
                }
                int noChukiLineLength = noChukiLine.length();
                if (this.autoChapterName) {
                    boolean isChapter = false;
                    //数字を含まない章名
                    for (int i = 0; i < this.chapterName.length; i++) {
                        String prefix = this.chapterName[i];
                        if (noChukiLine.startsWith(prefix)) {
                            if (noChukiLine.length() == prefix.length()) {
                                isChapter = true;
                                break;
                            } else if (isChapterSeparator(noChukiLine.charAt(prefix.length()))) {
                                isChapter = true;
                                break;
                            }
                        }
                    }
                    //数字を含む章名
                    if (!isChapter) {
                        for (int i = 0; i < this.chapterNumPrefix.length; i++) {
                            String prefix = this.chapterNumPrefix[i];
                            if (noChukiLine.startsWith(prefix)) {
                                int idx = prefix.length();
                                //次が数字かチェック
                                while (noChukiLineLength > idx && isChapterNum(noChukiLine.charAt(idx))) idx++;
                                //数字がなければ抽出しない
                                if (idx <= prefix.length())
                                    break;
                                //後ろをチェック prefixに対応するsuffixで回す
                                for (String suffix : this.chapterNumSuffix[i]) {
                                    if (!"".equals(suffix)) {
                                        if (noChukiLine.substring(idx).startsWith(suffix)) {
                                            idx += suffix.length();
                                            if (noChukiLine.length() == idx) {
                                                isChapter = true;
                                                break;
                                            } else if (isChapterSeparator(noChukiLine.charAt(idx))) {
                                                isChapter = true;
                                                break;
                                            }
                                        }
                                    } else {
                                        if (noChukiLine.length() == idx) {
                                            isChapter = true;
                                            break;
                                        } else if (isChapterSeparator(noChukiLine.charAt(idx))) {
                                            isChapter = true;
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                    }
                    if (isChapter) {
                        bookInfo.addChapterLineInfo(new ChapterLineInfo(lineNum, ChapterLineInfo.TYPE_CHAPTER_NAME, addSectionChapter, ChapterLineInfo.getLevel(ChapterLineInfo.TYPE_CHAPTER_NAME), lastEmptyLine == lineNum - 1, this.getChapterName(noRubyLine)));
                        //次の行を連結
                        if (this.useNextLineChapterName)
                            addNextChapterName = lineNum + 1;
                        //次の行を見出しとして利用
                        addChapterName = false;
                        //改ページ後のChapter出力を抑止
                        addSectionChapter = false;
                    }
                }
                if (this.autoChapterNumOnly || this.autoChapterNumTitle) {
                    //数字
                    int idx = 0;
                    while (noChukiLineLength > idx && isChapterNum(noChukiLine.charAt(idx))) idx++;
                    if (idx > 0) {
                        if (this.autoChapterNumOnly && noChukiLine.length() == idx || this.autoChapterNumTitle && noChukiLine.length() > idx && isChapterSeparator(noChukiLine.charAt(idx))) {
                            bookInfo.addChapterLineInfo(new ChapterLineInfo(lineNum, ChapterLineInfo.TYPE_CHAPTER_NUM, addSectionChapter, ChapterLineInfo.getLevel(ChapterLineInfo.TYPE_CHAPTER_NUM), lastEmptyLine == lineNum - 1, this.getChapterName(noRubyLine)));
                            //次の行を連結
                            if (this.useNextLineChapterName)
                                addNextChapterName = lineNum + 1;
                            //次の行を見出しとして利用しない
                            addChapterName = false;
                            //改ページ後のChapter出力を抑止
                            addSectionChapter = false;
                        }
                    }
                }
                if (this.autoChapterNumParen || this.autoChapterNumParenTitle) {
                    //括弧内数字のみ
                    for (int i = 0; i < this.chapterNumParenPrefix.length; i++) {
                        String prefix = this.chapterNumParenPrefix[i];
                        if (noChukiLine.startsWith(prefix)) {
                            int idx = prefix.length();
                            //次が数字かチェック
                            while (noChukiLineLength > idx && isChapterNum(noChukiLine.charAt(idx))) idx++;
                            //数字がなければ抽出しない
                            if (idx <= prefix.length())
                                break;
                            //後ろをチェック
                            String suffix = this.chapterNumParenSuffix[i];
                            if (noChukiLine.substring(idx).startsWith(suffix)) {
                                idx += suffix.length();
                                if (this.autoChapterNumParen && noChukiLine.length() == idx || this.autoChapterNumParenTitle && noChukiLine.length() > idx && isChapterSeparator(noChukiLine.charAt(idx))) {
                                    bookInfo.addChapterLineInfo(new ChapterLineInfo(lineNum, ChapterLineInfo.TYPE_CHAPTER_NUM, addSectionChapter, 13, lastEmptyLine == lineNum - 1, this.getChapterName(noRubyLine)));
                                    //次の行を連結
                                    if (this.useNextLineChapterName)
                                        addNextChapterName = lineNum + 1;
                                    //次の行を見出しとして利用しない
                                    addChapterName = false;
                                    //改ページ後のChapter出力を抑止
                                    addSectionChapter = false;
                                }
                            }
                        }
                    }
                }
            }
            //改ページ後の注記以外の本文を追加
            if (this.chapterSection && addSectionChapter) {
                //底本:は目次に出さない
                if (noRubyLine.length() > 2 && noRubyLine.charAt(0) == '底' && noRubyLine.charAt(1) == '本' && noRubyLine.charAt(2) == ':') {
                    //改ページ後のChapter出力を抑止
                    addSectionChapter = false;
                } else {
                    //記号のみの行は無視して次の行へ
                    String name = this.getChapterName(noRubyLine);
                    if (name.replaceAll("◇|◆|□|■|▽|▼|☆|★|*|+|×|†| ", "").length() > 0) {
                        bookInfo.addChapterLineInfo(new ChapterLineInfo(lineNum, ChapterLineInfo.TYPE_PAGEBREAK, true, 1, lastEmptyLine == lineNum - 1, name));
                        if (this.useNextLineChapterName)
                            addNextChapterName = lineNum + 1;
                        //改ページ後のChapter出力を抑止
                        addSectionChapter = false;
                    }
                }
            }
            //見出しの次の行&見出しでない
            if (addNextChapterName == lineNum && bookInfo.getChapterLineInfo(lineNum) == null) {
                //見出しの次の行を繋げる
                String name = this.getChapterName(noRubyLine);
                if (name.length() > 0) {
                    ChapterLineInfo info = bookInfo.getChapterLineInfo(lineNum - 1);
                    if (info != null)
                        info.joinChapterName(name);
                }
                addNextChapterName = -1;
            }
            //コメント行の後はタイトル取得はしない
            if (!firstCommentStarted) {
                String replaced = CharUtils.getChapterName(noRubyLine, 0);
                if (firstLineStart == -1) {
                    //文字の行が来たら先頭行開始
                    if (replaced.length() > 0) {
                        firstLineStart = this.lineNum;
                        firstLines[0] = line;
                    }
                } else {
                    //改ページで終了
                    if (isPageBreakLine(noRubyLine))
                        firstCommentStarted = true;
                    if (this.lineNum - firstLineStart > firstLines.length - 1) {
                        firstCommentStarted = true;
                    } else if (replaced.length() > 0) {
                        firstLines[this.lineNum - firstLineStart] = line;
                    }
                }
            }
            //前の2行を保存
            preLines[1] = preLines[0];
            preLines[0] = noRubyLine;
        }
        //行数設定
        bookInfo.totalLineNum = lineNum;
        if (inComment) {
            LogAppender.error(commentLineStart, "コメントが閉じていません");
        }
        //表題と著者を先頭行から設定
        bookInfo.setMetaInfo(titleType, pubFirst, firstLines, firstLineStart, firstCommentLineNum);
        //タイトルのChapter追加
        if (bookInfo.titleLine > -1) {
            String name = this.getChapterName(bookInfo.title);
            ChapterLineInfo chapterLineInfo = bookInfo.getChapterLineInfo(bookInfo.titleLine);
            if (chapterLineInfo == null)
                bookInfo.addChapterLineInfo(new ChapterLineInfo(bookInfo.titleLine, ChapterLineInfo.TYPE_TITLE, true, 0, false, name));
            else {
                chapterLineInfo.type = ChapterLineInfo.TYPE_TITLE;
                chapterLineInfo.level = 0;
            }
            //1行目がタイトルでなければ除外
            if (bookInfo.titleLine > 0) {
                for (int i = bookInfo.titleLine - 1; i >= 0; i--) bookInfo.removeChapterLineInfo(i);
            }
        }
        if (bookInfo.orgTitleLine > 0)
            bookInfo.removeChapterLineInfo(bookInfo.orgTitleLine);
        if (bookInfo.subTitleLine > 0)
            bookInfo.removeChapterLineInfo(bookInfo.subTitleLine);
        if (bookInfo.subOrgTitleLine > 0)
            bookInfo.removeChapterLineInfo(bookInfo.subOrgTitleLine);
        //前後2行前と2行後に3つ以上に抽出した見出しがある場合連続する見出しを除去
        if (this.excludeSeqencialChapter)
            bookInfo.excludeTocChapter();
        return bookInfo;
    } catch (Exception e) {
        e.printStackTrace();
        LogAppender.error(lineNum, "");
        throw e;
    }
}
Also used : Matcher(java.util.regex.Matcher) BookInfo(com.github.hmdev.info.BookInfo) ChapterLineInfo(com.github.hmdev.info.ChapterLineInfo) ImageInfo(com.github.hmdev.info.ImageInfo) IOException(java.io.IOException)

Example 4 with ChapterLineInfo

use of com.github.hmdev.info.ChapterLineInfo in project AozoraEpub3 by hmdev.

the class Epub3Writer method write.

/** epubファイルを出力
	 * @param converter 青空文庫テキスト変換クラス 画像のみの場合と切り替えて利用する
	 * @param src 青空文庫テキストファイルの入力Stream
	 * @param srcFile 青空文庫テキストファイル zip時の画像取得用
	 * @param zipTextFileName zipの場合はzip内のテキストファイルのパス付きファイル名
	 * @param epubFile 出力ファイル .epub拡張子
	 * @param bookInfo 書籍情報と縦横書き指定
	 * @param zipImageFileInfos zipの場合はzip内画像の情報 key=サブフォルダ付きの画像ファイル名
	 * @throws IOException */
public void write(AozoraEpub3Converter converter, BufferedReader src, File srcFile, String srcExt, File epubFile, BookInfo bookInfo, ImageInfoReader imageInfoReader) throws Exception {
    try {
        this.canceled = false;
        this.bookInfo = bookInfo;
        this.imageInfoReader = imageInfoReader;
        //インデックス初期化
        this.sectionIndex = 0;
        this.imageIndex = 0;
        this.sectionInfos.clear();
        this.chapterInfos.clear();
        this.vecGaijiInfo.clear();
        this.gaijiNameSet.clear();
        this.imageInfos.clear();
        this.outImageFileNames.clear();
        //Velocity用 共通コンテキスト設定
        this.velocityContext = new VelocityContext();
        //IDはタイトル著作者のハッシュで適当に生成
        String title = bookInfo.title == null ? "" : bookInfo.title;
        String creator = bookInfo.creator == null ? "" : bookInfo.creator;
        if ("".equals(bookInfo.creator))
            bookInfo.creator = null;
        //固有ID
        velocityContext.put("identifier", UUID.nameUUIDFromBytes((title + "-" + creator).getBytes()));
        //表紙の目次表示名
        velocityContext.put("cover_name", "表紙");
        //タイトル &<>はエスケープ
        velocityContext.put("title", CharUtils.escapeHtml(title));
        //タイトル読み &<>はエスケープ
        if (bookInfo.titleAs != null)
            velocityContext.put("titleAs", CharUtils.escapeHtml(bookInfo.titleAs));
        //著者 &<>はエスケープ
        velocityContext.put("creator", CharUtils.escapeHtml(creator));
        //著者読み &<>はエスケープ
        if (bookInfo.creatorAs != null)
            velocityContext.put("creatorAs", CharUtils.escapeHtml(bookInfo.creatorAs));
        //刊行者情報
        if (bookInfo.publisher != null)
            velocityContext.put("publisher", bookInfo.publisher);
        //書籍情報
        velocityContext.put("bookInfo", bookInfo);
        //更新日時
        velocityContext.put("modified", dateFormat.format(bookInfo.modified));
        //目次階層化
        velocityContext.put("navNest", this.navNest);
        //端末種別
        if (this.isKindle)
            velocityContext.put("kindle", true);
        //SVG画像出力
        if (this.isSvgImage)
            velocityContext.put("svgImage", true);
        //スタイル
        velocityContext.put("pageMargin", this.pageMargin);
        velocityContext.put("bodyMargin", this.bodyMargin);
        velocityContext.put("lineHeight", this.lineHeight);
        velocityContext.put("fontSize", this.fontSize);
        velocityContext.put("boldUseGothic", this.boldUseGothic);
        velocityContext.put("gothicUseBold", this.gothicUseBold);
        //出力先ePubのZipストリーム生成
        zos = new ZipArchiveOutputStream(new BufferedOutputStream(new FileOutputStream(epubFile)));
        //mimetypeは非圧縮
        //STOREDで格納しCRCとsizeを指定する必要がある
        ZipArchiveEntry mimeTypeEntry = new ZipArchiveEntry(MIMETYPE_PATH);
        FileInputStream fis = new FileInputStream(new File(templatePath + MIMETYPE_PATH));
        byte[] b = new byte[256];
        int len = fis.read(b);
        fis.close();
        CRC32 crc32 = new CRC32();
        crc32.update(b, 0, len);
        mimeTypeEntry.setMethod(ZipArchiveEntry.STORED);
        mimeTypeEntry.setCrc(crc32.getValue());
        mimeTypeEntry.setSize(len);
        zos.putArchiveEntry(mimeTypeEntry);
        zos.write(b, 0, len);
        b = null;
        zos.closeArchiveEntry();
        zos.setLevel(9);
        //テンプレートのファイルを格納
        for (String fileName : getTemplateFiles()) {
            writeFile(zos, fileName);
        }
        //サブパスの文字長
        int archivePathLength = 0;
        if (this.bookInfo.textEntryName != null)
            archivePathLength = this.bookInfo.textEntryName.indexOf('/') + 1;
        //zip出力用Writer
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(zos, "UTF-8"));
        //本文を出力
        this.writeSections(converter, src, bw, srcFile, srcExt, zos);
        if (this.canceled)
            return;
        //外字のcssを格納
        velocityContext.put("vecGaijiInfo", this.vecGaijiInfo);
        //スタイルと外字のcssを格納
        if (bookInfo.vertical) {
            zos.putArchiveEntry(new ZipArchiveEntry(OPS_PATH + CSS_PATH + VERTICAL_TEXT_CSS));
            bw = new BufferedWriter(new OutputStreamWriter(zos, "UTF-8"));
            Velocity.mergeTemplate(templatePath + OPS_PATH + CSS_PATH + VERTICAL_TEXT_CSS_VM, "UTF-8", velocityContext, bw);
            bw.flush();
            zos.closeArchiveEntry();
        } else {
            zos.putArchiveEntry(new ZipArchiveEntry(OPS_PATH + CSS_PATH + HORIZONTAL_TEXT_CSS));
            bw = new BufferedWriter(new OutputStreamWriter(zos, "UTF-8"));
            Velocity.mergeTemplate(templatePath + OPS_PATH + CSS_PATH + HORIZONTAL_TEXT_CSS_VM, "UTF-8", velocityContext, bw);
            bw.flush();
            zos.closeArchiveEntry();
        }
        //表紙をテンプレート+メタ情報から生成 先に出力すると外字画像出力で表紙の順番が狂う
        if (!bookInfo.imageOnly && (bookInfo.titlePageType == BookInfo.TITLE_MIDDLE || bookInfo.titlePageType == BookInfo.TITLE_HORIZONTAL)) {
            String vmFilePath = templatePath + OPS_PATH + XHTML_PATH + TITLE_M_VM;
            if (bookInfo.titlePageType == BookInfo.TITLE_HORIZONTAL) {
                converter.vertical = false;
                vmFilePath = templatePath + OPS_PATH + XHTML_PATH + TITLE_H_VM;
            }
            //ルビと外字画像注記と縦中横注記(縦書きのみ)のみ変換する
            String line = bookInfo.getTitleText();
            if (line != null)
                velocityContext.put("TITLE", converter.convertTitleLineToEpub3(line));
            line = bookInfo.getSubTitleText();
            if (line != null)
                velocityContext.put("SUBTITLE", converter.convertTitleLineToEpub3(line));
            line = bookInfo.getOrgTitleText();
            if (line != null)
                velocityContext.put("ORGTITLE", converter.convertTitleLineToEpub3(line));
            line = bookInfo.getSubOrgTitleText();
            if (line != null)
                velocityContext.put("SUBORGTITLE", converter.convertTitleLineToEpub3(line));
            line = bookInfo.getCreatorText();
            if (line != null)
                velocityContext.put("CREATOR", converter.convertTitleLineToEpub3(line));
            line = bookInfo.getSubCreatorText();
            if (line != null)
                velocityContext.put("SUBCREATOR", converter.convertTitleLineToEpub3(line));
            line = bookInfo.getSeriesText();
            if (line != null)
                velocityContext.put("SERIES", converter.convertTitleLineToEpub3(line));
            line = bookInfo.getPublisherText();
            if (line != null)
                velocityContext.put("PUBLISHER", converter.convertTitleLineToEpub3(line));
            //package.opf内で目次前に出力
            zos.putArchiveEntry(new ZipArchiveEntry(OPS_PATH + XHTML_PATH + TITLE_FILE));
            bw = new BufferedWriter(new OutputStreamWriter(zos, "UTF-8"));
            Velocity.mergeTemplate(vmFilePath, "UTF-8", velocityContext, bw);
            bw.flush();
            zos.closeArchiveEntry();
            velocityContext.put("title_page", true);
            //表題行を目次に出力するならtitle.xhtmlを追加 (本文内の行はchapterinfosに追加されていない)
            ChapterLineInfo titleLineInfo = bookInfo.getChapterLineInfo(bookInfo.titleLine);
            if (titleLineInfo != null) {
                chapterInfos.add(0, new ChapterInfo("title", null, bookInfo.title, ChapterLineInfo.LEVEL_TITLE));
            }
        }
        if (this.canceled)
            return;
        //表紙データと表示の画像情報
        byte[] coverImageBytes = null;
        ImageInfo coverImageInfo = null;
        if (bookInfo.coverFileName != null && bookInfo.coverFileName.length() > 0) {
            //表紙情報をimageInfosに追加
            try {
                //表紙設定解除
                for (ImageInfo imageInfo2 : imageInfos) {
                    imageInfo2.setIsCover(false);
                }
                BufferedInputStream bis;
                if (bookInfo.coverFileName.startsWith("http")) {
                    bis = new BufferedInputStream(new URL(bookInfo.coverFileName).openStream(), 8192);
                } else {
                    bis = new BufferedInputStream(new FileInputStream(new File(bookInfo.coverFileName)), 8192);
                }
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                IOUtils.copy(bis, baos);
                coverImageBytes = baos.toByteArray();
                bis.close();
                baos.close();
                ByteArrayInputStream bais = new ByteArrayInputStream(coverImageBytes);
                coverImageInfo = ImageInfo.getImageInfo(bais);
                bais.close();
                String ext = coverImageInfo.getExt();
                if (isKindle || ext.equals("jpeg"))
                    ext = "jpg";
                coverImageInfo.setId("0000");
                coverImageInfo.setOutFileName("0000." + ext);
                if (!ext.matches("^(png|jpg|jpeg|gif)$")) {
                    LogAppender.println("表紙画像フォーマットエラー: " + bookInfo.coverFileName);
                    coverImageInfo = null;
                } else {
                    coverImageInfo.setIsCover(true);
                    this.imageInfos.add(0, coverImageInfo);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else if (bookInfo.coverImage != null) {
            //すべてのページの表紙設定解除
            for (ImageInfo imageInfo2 : imageInfos) {
                imageInfo2.setIsCover(false);
            }
            //プレビューでトリミングされた表紙
            String ext = "jpg";
            if (bookInfo.coverExt != null) {
                ext = bookInfo.coverExt;
            } else if (bookInfo.coverImageIndex > -1) {
                ImageInfo imageInfo = imageInfoReader.getImageInfo(bookInfo.coverImageIndex);
                if (imageInfo != null)
                    ext = imageInfo.getExt();
            }
            if (isKindle || ext.equals("jpeg"))
                ext = "jpg";
            coverImageInfo = ImageInfo.getImageInfo(ext, bookInfo.coverImage, -1);
            coverImageInfo.setId("0000");
            coverImageInfo.setOutFileName("0000." + ext);
            coverImageInfo.setIsCover(true);
            this.imageInfos.add(0, coverImageInfo);
        } else {
            //本文にないzip内の表紙を出力対象に追加 (テキストからの相対パス)
            if (bookInfo.coverImageIndex > -1 && imageInfoReader.countImageFileNames() > bookInfo.coverImageIndex) {
                if (!"txt".equals(srcExt)) {
                    String imageFileName = imageInfoReader.getImageFileName(bookInfo.coverImageIndex);
                    if (imageFileName != null) {
                        ImageInfo imageInfo = imageInfoReader.getImageInfo(imageFileName);
                        if (imageInfo != null) {
                            imageFileName = imageFileName.substring(archivePathLength);
                            outImageFileNames.add(imageFileName);
                            //表紙フラグも設定
                            for (ImageInfo imageInfo2 : imageInfos) {
                                imageInfo2.setIsCover(false);
                            }
                            imageInfo.setIsCover(true);
                            if (!this.imageInfos.contains(imageInfo))
                                this.imageInfos.add(imageInfo);
                        }
                    }
                }
            }
        }
        //表紙ページ出力 先頭画像表示時は画像出力時にカバー指定するので出力しない
        if (bookInfo.insertCoverPage) {
            //追加用の情報取得にのみ使う
            ImageInfo insertCoverInfo = coverImageInfo;
            if (insertCoverInfo == null && bookInfo.coverImageIndex > -1) {
                //本文中の挿絵の場合
                insertCoverInfo = imageInfoReader.getImageInfo(bookInfo.coverImageIndex);
                if (insertCoverInfo != null) {
                    insertCoverInfo.setIsCover(true);
                    if (!bookInfo.imageOnly && insertCoverInfo.getId() == null) {
                        //zip内の画像で追加処理されていない
                        this.imageIndex++;
                        String imageId = decimalFormat.format(this.imageIndex);
                        insertCoverInfo.setId(imageId);
                        String ext = insertCoverInfo.getExt();
                        if (isKindle)
                            ext = "jpg";
                        insertCoverInfo.setOutFileName(imageId + "." + ext);
                    }
                }
            }
            if (insertCoverInfo != null) {
                SectionInfo sectionInfo = new SectionInfo("cover-page");
                if (this.imageSizeType != SectionInfo.IMAGE_SIZE_TYPE_AUTO) {
                    //画像が横長なら幅100% それ以外は高さ100%
                    if ((double) insertCoverInfo.getWidth() / insertCoverInfo.getHeight() >= (double) this.coverW / this.coverH)
                        sectionInfo.setImageFitW(true);
                    else
                        sectionInfo.setImageFitH(true);
                } else {
                    sectionInfo.setImageFitW(false);
                    sectionInfo.setImageFitH(false);
                }
                this.velocityContext.put("sectionInfo", sectionInfo);
                this.velocityContext.put("coverImage", insertCoverInfo);
                zos.putArchiveEntry(new ZipArchiveEntry(OPS_PATH + XHTML_PATH + COVER_FILE));
                bw = new BufferedWriter(new OutputStreamWriter(zos, "UTF-8"));
                Velocity.mergeTemplate(templatePath + OPS_PATH + XHTML_PATH + COVER_VM, "UTF-8", velocityContext, bw);
                bw.flush();
                zos.closeArchiveEntry();
            } else {
                //画像がなかったら表紙ページ無し
                bookInfo.insertCoverPage = false;
            }
        }
        //package.opf 出力
        velocityContext.put("sections", sectionInfos);
        velocityContext.put("images", imageInfos);
        zos.putArchiveEntry(new ZipArchiveEntry(OPS_PATH + PACKAGE_FILE));
        bw = new BufferedWriter(new OutputStreamWriter(zos, "UTF-8"));
        Velocity.mergeTemplate(templatePath + OPS_PATH + PACKAGE_VM, "UTF-8", velocityContext, bw);
        bw.flush();
        zos.closeArchiveEntry();
        //nullを除去
        for (int i = chapterInfos.size() - 1; i >= 0; i--) {
            if (chapterInfos.get(i).getChapterName() == null)
                chapterInfos.remove(i);
        }
        //表題のレベルを2つめと同じにする
        if (bookInfo.insertTitleToc && chapterInfos.size() >= 2) {
            chapterInfos.get(0).chapterLevel = chapterInfos.get(1).chapterLevel;
        }
        //目次の階層情報を設定
        //レベルを0から開始に変更
        int[] chapterCounts = new int[10];
        for (ChapterInfo chapterInfo : chapterInfos) {
            chapterCounts[chapterInfo.getChapterLevel()]++;
        }
        int[] newLevel = new int[10];
        int level = 0;
        for (int i = 0; i < chapterCounts.length; i++) {
            if (chapterCounts[i] > 0)
                newLevel[i] = level++;
        }
        for (ChapterInfo chapterInfo : chapterInfos) {
            chapterInfo.chapterLevel = newLevel[chapterInfo.chapterLevel];
        }
        //開始終了情報を追加 nav用
        //レベル0
        ChapterInfo preChapterInfo = new ChapterInfo(null, null, null, 0);
        for (ChapterInfo chapterInfo : chapterInfos) {
            if (preChapterInfo != null) {
                //開始
                chapterInfo.levelStart = Math.max(0, chapterInfo.chapterLevel - preChapterInfo.chapterLevel);
                //終了
                preChapterInfo.levelEnd = Math.max(0, preChapterInfo.chapterLevel - chapterInfo.chapterLevel);
            }
            preChapterInfo = chapterInfo;
        }
        //一番最後は閉じる
        if (chapterInfos.size() > 0) {
            ChapterInfo chapterInfo = chapterInfos.lastElement();
            if (chapterInfo != null)
                chapterInfo.levelEnd = chapterInfo.chapterLevel;
        }
        int ncxDepth = 1;
        if (this.ncxNest) {
            int minLevel = 99;
            int maxLevel = 0;
            //navPointを閉じる回数をlevelEndに設定
            //navPointを開始したレベルidxに1を設定
            int[] navPointLevel = new int[10];
            preChapterInfo = null;
            for (ChapterInfo chapterInfo : chapterInfos) {
                if (preChapterInfo != null) {
                    int preLevel = preChapterInfo.chapterLevel;
                    int curLevel = chapterInfo.chapterLevel;
                    minLevel = Math.min(minLevel, curLevel);
                    maxLevel = Math.max(maxLevel, curLevel);
                    navPointLevel[preLevel] = 1;
                    if (preLevel < curLevel) {
                        //前より小さい場合
                        preChapterInfo.navClose = 0;
                    } else if (preLevel > curLevel) {
                        //前より大きい
                        int close = 0;
                        for (int i = curLevel; i < navPointLevel.length; i++) {
                            if (navPointLevel[i] == 1) {
                                close++;
                                navPointLevel[i] = 0;
                            }
                        }
                        preChapterInfo.navClose = close;
                    } else {
                        preChapterInfo.navClose = 1;
                        navPointLevel[preLevel] = 0;
                    }
                }
                preChapterInfo = chapterInfo;
            }
            if (minLevel < maxLevel)
                ncxDepth = maxLevel - minLevel + 1;
            //一番最後は閉じる
            if (chapterInfos.size() > 0) {
                ChapterInfo chapterInfo = chapterInfos.lastElement();
                if (chapterInfo != null) {
                    int close = 1;
                    for (int i = 0; i < navPointLevel.length; i++) {
                        if (navPointLevel[i] == 1) {
                            close++;
                        }
                    }
                    chapterInfo.navClose = close;
                }
            }
        }
        //velocityに設定 1~
        velocityContext.put("ncx_depth", ncxDepth);
        //出力前に縦中横とエスケープ処理
        if (!bookInfo.imageOnly) {
            converter.vertical = bookInfo.tocVertical;
            int spaceHyphenation = converter.getSpaceHyphenation();
            converter.setSpaceHyphenation(0);
            StringBuilder buf = new StringBuilder();
            for (ChapterInfo chapterInfo : chapterInfos) {
                buf.setLength(0);
                String converted = CharUtils.escapeHtml(chapterInfo.getChapterName());
                if (bookInfo.tocVertical) {
                    converted = converter.convertTcyText(converted);
                }
                chapterInfo.setChapterName(converted);
            }
            //戻す
            converter.vertical = bookInfo.vertical;
            converter.setSpaceHyphenation(spaceHyphenation);
        }
        //navファイル
        velocityContext.put("chapters", chapterInfos);
        zos.putArchiveEntry(new ZipArchiveEntry(OPS_PATH + XHTML_PATH + XHTML_NAV_FILE));
        bw = new BufferedWriter(new OutputStreamWriter(zos, "UTF-8"));
        Velocity.mergeTemplate(templatePath + OPS_PATH + XHTML_PATH + XHTML_NAV_VM, "UTF-8", velocityContext, bw);
        bw.flush();
        zos.closeArchiveEntry();
        //tocファイル
        velocityContext.put("chapters", chapterInfos);
        zos.putArchiveEntry(new ZipArchiveEntry(OPS_PATH + TOC_FILE));
        bw = new BufferedWriter(new OutputStreamWriter(zos, "UTF-8"));
        Velocity.mergeTemplate(templatePath + OPS_PATH + TOC_VM, "UTF-8", velocityContext, bw);
        bw.flush();
        zos.closeArchiveEntry();
        if (src != null)
            src.close();
        if (this.canceled)
            return;
        //プログレスバーにテキスト進捗分を追加
        if (this.jProgressBar != null && !bookInfo.imageOnly)
            this.jProgressBar.setValue(bookInfo.totalLineNum / 10);
        //フォントファイル格納
        if (!bookInfo.imageOnly) {
            File fontsPath = new File(templatePath + OPS_PATH + FONTS_PATH);
            if (fontsPath.exists()) {
                for (File fontFile : fontsPath.listFiles()) {
                    String outFileName = OPS_PATH + FONTS_PATH + fontFile.getName();
                    zos.putArchiveEntry(new ZipArchiveEntry(outFileName));
                    fis = new FileInputStream(new File(templatePath + outFileName));
                    IOUtils.copy(fis, zos);
                    fis.close();
                    zos.closeArchiveEntry();
                }
            }
        }
        //外字ファイル格納
        for (GaijiInfo gaijiInfo : this.vecGaijiInfo) {
            File gaijiFile = gaijiInfo.getFile();
            if (gaijiFile.exists()) {
                String outFileName = OPS_PATH + GAIJI_PATH + gaijiFile.getName();
                zos.putArchiveEntry(new ZipArchiveEntry(outFileName));
                fis = new FileInputStream(gaijiFile);
                IOUtils.copy(fis, zos);
                fis.close();
                zos.closeArchiveEntry();
            }
        }
        zos.setLevel(0);
        //表紙編集時のイメージ出力
        if (coverImageInfo != null) {
            try {
                //kindleの場合は常にjpegに変換
                if (isKindle) {
                    String imgExt = coverImageInfo.getExt();
                    if (!imgExt.startsWith("jp")) {
                        if (bookInfo.coverImage == null) {
                            ByteArrayInputStream bais = new ByteArrayInputStream(coverImageBytes);
                            bookInfo.coverImage = ImageUtils.readImage(imgExt, bais);
                            bais.close();
                        }
                        coverImageInfo.setExt("jpeg");
                    }
                }
                if (bookInfo.coverImage != null) {
                    //プレビューで編集されている場合
                    zos.putArchiveEntry(new ZipArchiveEntry(OPS_PATH + IMAGES_PATH + coverImageInfo.getOutFileName()));
                    this.writeCoverImage(bookInfo.coverImage, zos, coverImageInfo);
                    zos.closeArchiveEntry();
                    //同じ画像が使われている場合は以後はファイルから読み込ませる
                    bookInfo.coverImage = null;
                } else {
                    ByteArrayInputStream bais = new ByteArrayInputStream(coverImageBytes);
                    zos.putArchiveEntry(new ZipArchiveEntry(OPS_PATH + IMAGES_PATH + coverImageInfo.getOutFileName()));
                    this.writeCoverImage(bais, zos, coverImageInfo);
                    zos.closeArchiveEntry();
                    bais.close();
                }
                //カバー画像は出力済みなので削除
                imageInfos.remove(0);
                if (this.jProgressBar != null)
                    this.jProgressBar.setValue(this.jProgressBar.getValue() + 10);
            } catch (Exception e) {
                e.printStackTrace();
                LogAppender.error("表紙画像取得エラー: " + bookInfo.coverFileName);
            }
        }
        if (this.canceled)
            return;
        //本文画像出力 (画像のみの場合は出力済)
        if ("txt".equals(srcExt)) {
            //txtの場合はファイルシステムから取得
            for (String srcImageFileName : imageInfoReader.getImageFileNames()) {
                //拡張子修正
                srcImageFileName = imageInfoReader.correctExt(srcImageFileName);
                if (outImageFileNames.contains(srcImageFileName)) {
                    ImageInfo imageInfo = imageInfoReader.getImageInfo(srcImageFileName);
                    if (imageInfo == null) {
                        LogAppender.println("[WARN] 画像ファイルなし: " + srcImageFileName);
                    } else {
                        File imageFile = imageInfoReader.getImageFile(srcImageFileName);
                        if (imageFile.exists()) {
                            fis = new FileInputStream(imageFile);
                            zos.putArchiveEntry(new ZipArchiveEntry(OPS_PATH + IMAGES_PATH + imageInfo.getOutFileName()));
                            this.writeImage(new BufferedInputStream(fis, 8192), zos, imageInfo);
                            zos.closeArchiveEntry();
                            fis.close();
                            outImageFileNames.remove(srcImageFileName);
                        }
                    }
                }
                if (this.canceled)
                    return;
                if (this.jProgressBar != null)
                    this.jProgressBar.setValue(this.jProgressBar.getValue() + 10);
            }
        } else if (!bookInfo.imageOnly) {
            if ("rar".equals(srcExt)) {
                ////////////////////////////////
                //Rar
                Archive archive = new Archive(srcFile);
                try {
                    for (FileHeader fileHeader : archive.getFileHeaders()) {
                        if (!fileHeader.isDirectory()) {
                            String entryName = fileHeader.getFileNameW();
                            if (entryName.length() == 0)
                                entryName = fileHeader.getFileNameString();
                            entryName = entryName.replace('\\', '/');
                            //アーカイブ内のサブフォルダは除外してテキストからのパスにする
                            String srcImageFileName = entryName.substring(archivePathLength);
                            if (outImageFileNames.contains(srcImageFileName)) {
                                InputStream is = archive.getInputStream(fileHeader);
                                try {
                                    this.writeArchiveImage(srcImageFileName, is);
                                } finally {
                                    is.close();
                                }
                            }
                        }
                    }
                } finally {
                    archive.close();
                }
            } else {
                ////////////////////////////////
                //Zip
                ZipArchiveInputStream zis = new ZipArchiveInputStream(new BufferedInputStream(new FileInputStream(srcFile), 65536), "MS932", false);
                try {
                    ArchiveEntry entry;
                    while ((entry = zis.getNextZipEntry()) != null) {
                        //アーカイブ内のサブフォルダは除外してテキストからのパスにする
                        String srcImageFileName = entry.getName().substring(archivePathLength);
                        if (outImageFileNames.contains(srcImageFileName)) {
                            this.writeArchiveImage(srcImageFileName, zis);
                        }
                    }
                } finally {
                    zis.close();
                }
            }
        }
        //エラーがなければ100%
        if (this.jProgressBar != null)
            this.jProgressBar.setValue(this.jProgressBar.getMaximum());
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            //ePub3出力ファイルを閉じる
            if (zos != null)
                zos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        //メンバ変数解放
        this.velocityContext = null;
        this.bookInfo = null;
        this.imageInfoReader = null;
    }
}
Also used : ChapterInfo(com.github.hmdev.info.ChapterInfo) Archive(com.github.junrar.Archive) CRC32(java.util.zip.CRC32) VelocityContext(org.apache.velocity.VelocityContext) ZipArchiveEntry(org.apache.commons.compress.archivers.zip.ZipArchiveEntry) ArchiveEntry(org.apache.commons.compress.archivers.ArchiveEntry) URL(java.net.URL) BufferedWriter(java.io.BufferedWriter) BufferedInputStream(java.io.BufferedInputStream) ZipArchiveEntry(org.apache.commons.compress.archivers.zip.ZipArchiveEntry) ImageInfo(com.github.hmdev.info.ImageInfo) BufferedOutputStream(java.io.BufferedOutputStream) FileHeader(com.github.junrar.rarfile.FileHeader) ZipArchiveInputStream(org.apache.commons.compress.archivers.zip.ZipArchiveInputStream) BufferedInputStream(java.io.BufferedInputStream) ByteArrayInputStream(java.io.ByteArrayInputStream) FileInputStream(java.io.FileInputStream) ZipArchiveInputStream(org.apache.commons.compress.archivers.zip.ZipArchiveInputStream) InputStream(java.io.InputStream) ChapterLineInfo(com.github.hmdev.info.ChapterLineInfo) ZipArchiveOutputStream(org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream) ByteArrayOutputStream(java.io.ByteArrayOutputStream) FileInputStream(java.io.FileInputStream) IOException(java.io.IOException) ByteArrayInputStream(java.io.ByteArrayInputStream) FileOutputStream(java.io.FileOutputStream) OutputStreamWriter(java.io.OutputStreamWriter) SectionInfo(com.github.hmdev.info.SectionInfo) GaijiInfo(com.github.hmdev.info.GaijiInfo) File(java.io.File)

Example 5 with ChapterLineInfo

use of com.github.hmdev.info.ChapterLineInfo in project AozoraEpub3 by hmdev.

the class AozoraEpub3Converter method printLineBuffer.

/** 行の文字列を出力
	 * 改ページフラグがあれば改ページ処理を行う
	 * @param out 出力先
	 * @param buf 出力する行
	 * @param noBr pタグで括れない次以降の行で閉じるブロック注記がある場合
	 * @param chapterLevel Chapterレベル 指定無し=0, 大見出し=1, 中見出し=2, 見出し=2, 小見出し=3 (パターン抽出時は設定に合わせるか目次リストで選択したレベル)
	 * @throws IOException */
private void printLineBuffer(BufferedWriter out, StringBuilder buf, int lineNum, boolean noBr) throws IOException {
    String line = buf.toString();
    int length = buf.length();
    //すべて空白は空行にする
    if (CharUtils.isSpace(line)) {
        line = "";
        length = 0;
    }
    int idIdx = 1;
    String chapterId = null;
    ChapterLineInfo chapterLineInfo = null;
    //空白除去の時はスペースのみの行は空行扱い
    if (this.removeEmptyLine > 0 && length > 0 && CharUtils.isSpace(line)) {
        line = "";
        length = 0;
    }
    if (length == 0) {
        //空行なら行数をカウント 左右中央の時の本文前の空行は無視
        if (!this.skipMiddleEmpty && !noBr) {
            this.printEmptyLines++;
        }
        //バッファクリア
        buf.setLength(0);
        return;
    }
    //バッファ内の文字列出力
    //見出し階層レベル
    chapterLineInfo = this.bookInfo.getChapterLineInfo(lineNum);
    //タグの階層をチェック (強制改ページ判別用に先にやっておく)
    int tagStart = 0;
    int tagEnd = 0;
    boolean inTag = false;
    for (int i = 0; i < length; i++) {
        if (inTag) {
            if (line.charAt(i) == '/' && line.charAt(i + 1) == '>')
                tagEnd++;
            if (line.charAt(i) == '>')
                inTag = false;
        } else {
            if (line.charAt(i) == '<') {
                if (i < length - 1 && line.charAt(i + 1) == '/')
                    tagEnd++;
                else
                    tagStart++;
                inTag = true;
            }
        }
    }
    if (out != null) {
        //改ページトリガが設定されていない&タグの外
        if (this.forcePageBreak && this.pageBreakTrigger == null && this.tagLevel == 0) {
            //行単位で強制改ページ
            if (this.pageByteSize > this.forcePageBreakSize) {
                this.setPageBreakTrigger(pageBreakNoChapter);
            } else {
                if (forcePageBreakEmptyLine > 0 && this.printEmptyLines >= forcePageBreakEmptyLine && this.pageByteSize > this.forcePageBreakEmptySize) {
                    //空行での分割
                    this.setPageBreakTrigger(pageBreakNoChapter);
                } else if (forcePageBreakChapterLevel > 0 && this.pageByteSize > this.forcePageBreakChapterSize) {
                    //章での分割 次の行が見出しで次の行がタグの中になる場合1行前で改ページ
                    if (chapterLineInfo != null)
                        this.setPageBreakTrigger(pageBreakNoChapter);
                    else if (tagStart - tagEnd > 0 && this.bookInfo.getChapterLevel(lineNum + 1) > 0)
                        this.setPageBreakTrigger(pageBreakNoChapter);
                }
            }
        }
        //改ページフラグが設定されていて、空行で無い場合
        if (this.pageBreakTrigger != null) {
            //改ページ処理
            if (this.pageBreakTrigger.pageType != PageBreakType.PAGE_NORMAL) {
                //左右中央
                this.writer.nextSection(out, lineNum, this.pageBreakTrigger.pageType, PageBreakType.IMAGE_PAGE_NONE, null);
            } else {
                //その他
                this.writer.nextSection(out, lineNum, PageBreakType.PAGE_NORMAL, this.pageBreakTrigger.imagePageType, this.pageBreakTrigger.srcFileName);
            }
            //ページ情報初期化
            this.pageByteSize = 0;
            this.sectionCharLength = 0;
            if (tagLevel > 0)
                LogAppender.error(lineNum, "タグが閉じていません");
            this.tagLevel = 0;
            this.lineIdNum = 0;
            this.pageBreakTrigger = null;
        }
        this.skipMiddleEmpty = false;
        //空行は行数がカウントされているので文字出力前に出力
        if (this.printEmptyLines > 0) {
            String br = chukiMap.get("改行")[0];
            int lines = Math.min(this.maxEmptyLine, this.printEmptyLines - this.removeEmptyLine);
            //見出し後3行以内開始の空行は1行は残す
            if (lastChapterLine >= lineNum - this.printEmptyLines - 2) {
                lines = Math.max(1, lines);
            }
            for (int i = lines - 1; i >= 0; i--) {
                out.write("<p>");
                out.write(br);
                out.write("</p>\n");
            }
            this.pageByteSize += (br.length() + 8) * lines;
            this.printEmptyLines = 0;
        }
        this.lineIdNum++;
        if (noBr) {
            //見出し用のID設定
            if (chapterLineInfo != null) {
                chapterId = "kobo." + this.lineIdNum + "." + (idIdx++);
                if (line.startsWith("<")) {
                    //タグがあるのでIDを設定
                    line = line.replaceFirst("(<[\\d|\\w]+)", "$1 id=\"" + chapterId + "\"");
                } else {
                    //タグでなければ一文字目をspanに入れる
                    out.write("<span id=\"" + chapterId + "\">" + line.charAt(0) + "</span>");
                    this.pageByteSize += (chapterId.length() + 20);
                    line = line.substring(1);
                }
            }
        } else {
            //改行用のp出力 見出しなら強制ID出力 koboの栞用IDに利用可能なkobo.のIDで出力
            if (this.withMarkId || (chapterLineInfo != null && !chapterLineInfo.pageBreakChapter)) {
                chapterId = "kobo." + this.lineIdNum + "." + (idIdx++);
                out.write("<p id=\"" + chapterId + "\">");
                this.pageByteSize += (chapterId.length() + 14);
            } else {
                out.write("<p>");
                this.pageByteSize += 7;
            }
        }
        out.write(line);
        //ページバイト数加算
        if (this.forcePageBreak)
            this.pageByteSize += line.getBytes("UTF-8").length;
        //改行のpを閉じる
        if (!noBr) {
            out.write("</p>\n");
        }
        //見出しのChapterをWriterに追加 同じ行で数回呼ばれるので初回のみ
        if (chapterLineInfo != null && lastChapterLine != lineNum) {
            String name = chapterLineInfo.getChapterName();
            if (name != null && name.length() > 0) {
                //自動抽出で+10されているのは1桁のレベルに戻す
                if (chapterLineInfo.pageBreakChapter)
                    this.writer.addChapter(null, name, chapterLineInfo.level % 10);
                else
                    this.writer.addChapter(chapterId, name, chapterLineInfo.level % 10);
                lastChapterLine = lineNum;
            }
        }
        this.sectionCharLength += length;
    }
    //タグの階層を変更
    this.tagLevel += tagStart - tagEnd;
    //バッファクリア
    buf.setLength(0);
}
Also used : ChapterLineInfo(com.github.hmdev.info.ChapterLineInfo)

Aggregations

ChapterLineInfo (com.github.hmdev.info.ChapterLineInfo)5 IOException (java.io.IOException)3 ImageInfo (com.github.hmdev.info.ImageInfo)2 File (java.io.File)2 BookInfo (com.github.hmdev.info.BookInfo)1 ChapterInfo (com.github.hmdev.info.ChapterInfo)1 GaijiInfo (com.github.hmdev.info.GaijiInfo)1 SectionInfo (com.github.hmdev.info.SectionInfo)1 Archive (com.github.junrar.Archive)1 FileHeader (com.github.junrar.rarfile.FileHeader)1 Dimension (java.awt.Dimension)1 Point (java.awt.Point)1 BufferedInputStream (java.io.BufferedInputStream)1 BufferedOutputStream (java.io.BufferedOutputStream)1 BufferedWriter (java.io.BufferedWriter)1 ByteArrayInputStream (java.io.ByteArrayInputStream)1 ByteArrayOutputStream (java.io.ByteArrayOutputStream)1 FileInputStream (java.io.FileInputStream)1 FileOutputStream (java.io.FileOutputStream)1 InputStream (java.io.InputStream)1