Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PowerPoint ファイルをスライドショーにすると真っ黒画像に変換される #770

Closed
Monota opened this issue Jun 24, 2017 · 9 comments

Comments

@Monota
Copy link
Contributor

Monota commented Jun 24, 2017

現状、PowerPoint ファイルのスライドショー変換を行うと、ほぼ 100% の確率で真っ黒画像に変換されます。

PptxSlideShowParser の実装を見ると、

for (Slide<?, ?> slide : slides) {
    String title = slide.getTitle();
    System.out.println("Rendering slide " + slideNo + (title == null ? "" : ": " + title));

    BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    //ImageIOUtil.writeImage(img, outputDir.getAbsolutePath() + "/" + (slideNo) + ".png", 300);
    super.writeImage(img, outputDir.getAbsolutePath() + "/" + (slideNo) + ".png");
    slideNo++;
}

となっていて、Slide の内容を BufferedImage に反映していないように思いました。そこで以下のようにコードを変えたらスライドが生成されるようにはなったのですが、今度は #509 で指摘されているような事象が起きました。

for (Slide<?, ?> slide : slides) {
    String title = slide.getTitle();
    System.out.println("Rendering slide " + slideNo + (title == null ? "" : ": " + title));

    BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    Graphics2D graphics = img.createGraphics();
    graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
    graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
    graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
    slide.draw(graphics);
    img.flush();
    //ImageIOUtil.writeImage(img, outputDir.getAbsolutePath() + "/" + (slideNo) + ".png", 300);
    super.writeImage(img, outputDir.getAbsolutePath() + "/" + (slideNo) + ".png");
    graphics.dispose();
    slideNo++;
}

おそらく d15d24a で修正する前の内容に一部戻ってしまうかなと思うのですが、こちら PR お送りした方が良いでしょうか?

@Monota
Copy link
Contributor Author

Monota commented Jun 24, 2017

あと、@koda-masaru さんの方でも過去に調べられたとは思いますが、私の手持ちの環境でも色々と試してみて、現象を整理したところ以下の結果になりました。

Windows 10

PowerPointで編集時、フォントを変えずに保存している部分は文字化けする。フォントを変えた部分は文字化けしない。

macOS 10.12

試した限りだと常に文字化けしない。

CentOS 7.3

X Window System がインストールされていて、なおかつ日本語フォントがインストールされていなければ文字化けしない(もしかすると後述のフォント固定後だけ文字化けしないのかもしれません)。やったことは、CentOS Minimal をインストールして以下のコマンドを実行しました。

yum groupinstall "X Window System"
yum install ipa-gothic-fonts ipa-mincho-fonts ipa-pgothic-fonts ipa-pmincho-fonts

使用した PowerPoint は 2013 です。

@Monota
Copy link
Contributor Author

Monota commented Jun 24, 2017

余談ですが、Windows 10 については、特定のテキストをフォントを変えずに保存すると、なぜか POI にはフォント指定が Calibri として解釈されているようでした。このため日本語文字がないので□で出力されるように見えました。これが POI の実装に起因するのか、PowerPoint の仕様なのかまでは調べられませんでしたが、画像変換時にフォントを全て SansSerif などに固定すると文字化けしないようになりました(が、フォントが変わると元のスライドから見た目も変わります)。

@koda-masaru
Copy link
Contributor

@Monota さん
いつもありがとうございます 🙇

PR お送りした方が良いでしょうか?

PRお願いします。

なぜか POI にはフォント指定が Calibri として解釈されている

OSのデフォルトでフォントが決まるのかもしれません。私もいろいろ試してみたのですが、PowerPointでスライドショー作成するとレイアウトが崩れたり文字化けしたりすることが多く、私が運営している環境では「PDFだけにして」とお願いしてる感じです。

ただ、PDFでもちゃんと日本語環境がセットアップできていないと、日本語は文字化けするようです。
この点で、スライドショー表示を利用する場合、Knowledgeをホストする環境は、WindowsやMacがうまく動くようです。(#509

パワーポイントからの変換があまりに不安定な場合は、PDFだけにした方が良いのかもしれませんね。

@Monota
Copy link
Contributor Author

Monota commented Jun 25, 2017

@koda-masaru さん、ありがとうございます。PR お送りしました。

たしかに、Windows の PowerPoint だと Calibri が英語フォントのデフォルトのようです。
日本語版は、英語版と違って英数字フォントと日本語フォントの両方が指定可能で、かつ日本語入力時に日本語フォントが、英数字入力時に英数字フォントが使用される複雑な仕組みのため、POI でそこまで吸収できていないのかもしれないです。

英語版
日本語版

一応、フォントを固定にしたときのソースコードを貼り付けておきます。

for (Slide<?, ?> slide : slides) {
    String title = slide.getTitle();
    System.out.println("Rendering slide " + slideNo + (title == null ? "" : ": " + title));

    for (Object obj : slide.getShapes()) {
        if (obj instanceof XSLFAutoShape) {
            XSLFAutoShape shape = (XSLFAutoShape) obj;
            for (TextParagraph paragraph : shape.getTextParagraphs()) {
                System.out.println(paragraph.getDefaultFontFamily());
                for (Object run : paragraph.getTextRuns()) {
                    if (run instanceof XSLFTextRun) {
                        ((XSLFTextRun) run).setFontFamily(Font.SANS_SERIF);
                    }
                }
            }
        }
    }

    BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    Graphics2D graphics = img.createGraphics();
    graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
    graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
    graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
    slide.draw(graphics);
    img.flush();
    //ImageIOUtil.writeImage(img, outputDir.getAbsolutePath() + "/" + (slideNo) + ".png", 300);
    super.writeImage(img, outputDir.getAbsolutePath() + "/" + (slideNo) + ".png");
    graphics.dispose();
    slideNo++;
}

PowerPoint については、もとのデザインを完全に再現して画像変換するのは難しいかもしれないですね。中身を軽く見ることができる程度の位置づけなら便利かもしれません。
PDF についても時間があるときに確認してみます。

@koda-masaru
Copy link
Contributor

プルリクありがとうございました!次回のリリースに含まれますので、少々お待ち下さい。

@Monota
Copy link
Contributor Author

Monota commented Jul 1, 2017

ご対応ありがとうございました。

本件とても気になったのでもう少し調べてみたのですが、解決方法は見つかっていません。

https://stackoverflow.com/questions/40931958/what-is-the-default-japanese-font-when-using-apache-poi-hslfslide-draw

に書いてあるようなフォントのフォールバックの仕組みを利用して、

for (Slide<?, ?> slide : slides) {
    String title = slide.getTitle();
    System.out.println("Rendering slide " + slideNo + (title == null ? "" : ": " + title));
    GraphicsEnvironment globalEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();
    try (InputStream is = ClassLoader.getSystemResourceAsStream("font/ipagp.ttf")) {
        Font font = Font.createFont(Font.TRUETYPE_FONT, is);
        globalEnvironment.registerFont(font);
    } catch (FontFormatException ffe) {
        ffe.printStackTrace();
    }
    Map<String,String> fallbackMap = new HashMap<String,String>();
    fallbackMap.put("*", "IPAPGothic");
    slide.getTitle();
    BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    Graphics2D graphics = img.createGraphics();
    graphics.setRenderingHint(Drawable.FONT_FALLBACK, fallbackMap);
    graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
    graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
    graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
    slide.draw(graphics);
    img.flush();
    //ImageIOUtil.writeImage(img, outputDir.getAbsolutePath() + "/" + (slideNo) + ".png", 300);
    super.writeImage(img, outputDir.getAbsolutePath() + "/" + (slideNo) + ".png");
    graphics.dispose();
    slideNo++;
}

のように、フォントがない場合はローカルフォント(この場合は IPA Pゴシック)にフォールバックするようにすることで Windows では対応できました。しかし CUI しかない Linux では □ になるので、まだ不十分なようです。

そろそろ諦めようかなと思っていますが備忘録として残しておきます。

@koda-masaru
Copy link
Contributor

@Monota さん
詳細に調べていただきありがとうございます 🙇
とっても参考になります。

そろそろ諦めようかなと思っていますが備忘録として残しておきます。

いったん、本issueは次回のリリースでクローズとして、今後日本語のところで要望などが出てきたら、再度調べるということで良いかと思っています。(そのころには、ライブラリのバージョンも上がっているかもしれませんし)

@Monota
Copy link
Contributor Author

Monota commented Jul 1, 2017

いったん、本issueは次回のリリースでクローズとして、今後日本語のところで要望などが出てきたら、再度調べるということで良いかと思っています。(そのころには、ライブラリのバージョンも上がっているかもしれませんし)

上記内容で問題ありません。
根本的な原因が気になったので調べていました(し、ほかの不具合も原因が気になって横やりを入れてしまうことがありますがご容赦いただけますと幸いです)。

@koda-masaru
Copy link
Contributor

Release v1.10.0 pre1 としてリリースしたためクローズします。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants