iPhone で撮影した画像が意図した向きで表示されない件

iPhone で撮影した画像ですが、iOS 上の Safari や、facebook のリンクのプレビュー画面で意図した向きで表示されない件が気になっていたので、対策を考えてみました。

原因は、撮影した向きでは画像が保存されず、向きを補正する情報が保存されることに起因すると推定しているのですが、対策からすれば、向きを補正する情報を読み取り、正しい向きでシンプルがデータとして再構成すれば良い、ということになるかと思うわけです。

不用な Exif データなども削除すれば、多少なりともトラフィクの軽減にもなるわけですし、そういう部分も掘り下げたいところではあるんですが、それ以前に、iPhone で撮影する場合、画素数の調整なんかができない気がするので、アホのように巨大な画像ファイルになるので、それを手当しなければならず、現状は、Wordpress のプラグインで、imsanity というものを使って対策をしているのですが、これ自体は、リサイズしかしてくれないので、たたき台にするにしても、もっとマシなものがあるだろう、ということで探してみました。

そうしたところ、fix image rotation というものがあり、早速落としてみました。

動作的には、filter_wp_handle_upload_prefilter で、ファイルアップロード時にフックして、実処理は、fixImageOrientation でやっているわけですが、ここでは、WP_Image_Editor インスタンスが実際のイメージ処理を行っています。

調べてみたところ、あまり詳しいマニュアルはなかったのですが、

$image = wp_get_image_editor( 'cool_image.jpg' );
if ( ! is_wp_error( $image ) ) {
    $image->rotate( 90 );
    $image->resize( 300, 300, true );
    $image->save( 'new_image.jpg' );
}

ということで、リサイズと回転のサンプルコードがあり、つまり、リサイズ機能も有しているようなので、少し書き換えれば、サイズ調整も可能になりそうに思いました。

insanity にはすでにアップロード済みのファイルを修正する機能もあるんで、そっちをベースにした方がいいかもしれないし、あるいは、そのものずばりのプラグインもあるような予感もするんだけど、まあ、勉強も兼ねて、ちょっと作ってみました。

<?php

/**
 * @package Image Filter
 * @version 1.0
 */
/*
  Plugin Name: Image Filter
  Description: Image Filter plugin fixes image size and image orientation based on EXIF data.
  Author: Osamu Shigematsu
  Version: 1.0
  Author URI: http://shigematsu.org
 */

if (!defined('ABSPATH'))
    exit; // Exit if accessed directly

if (!class_exists('ImageFilter')) {
class ImageFilter {
    public function __construct() {
        add_filter('wp_handle_upload_prefilter',
            array($this, 'filter_wp_handle_upload_prefilter'), 10, 1);

        add_filter('wp_handle_upload',
            array($this, 'filter_wp_handle_upload'), 1, 3);
    }

    public function filter_wp_handle_upload($file) {
        $suffix = strtolower(substr($file['file'], strrpos($file['file'], '.', -1) + 1));
        if (in_array($suffix, array('jpg', 'jpeg', 'png', 'gif'))) {
            $this->fixImage($file['file']);
        }
        return $file;
    }

    public function filter_wp_handle_upload_prefilter($file) {
        $suffix = strtolower(substr($file['file'], strrpos($file['file'], '.', -1) + 1));
        if (in_array($suffix, array('jpg', 'jpeg', 'png', 'gif'))) {
            $this->fixImage($file['tmp_name']);
        }
        return $file;
    }

    public function fixImage($file) {
        $fixed = false;
        $editor = wp_get_image_editor($file);
        if (!is_wp_error($editor)) {
            // reize image (if needed)
            $MAX_WIDTH = $MAX_HEIGHT = 1600;
            $size = $editor->get_size();
            $width = $size['width'];
            $height = $size['height'];
            if ($width > $MAX_WIDTH ||
                $height > $MAX_HEIGHT) {
                $editor->resize($MAX_WIDTH, $MAX_HEIGHT, false);
                $fixed = true;
            }

            // fix orientation
            // http://dqn.sakusakutto.jp/2009/02/jpegexiforientaion.html
            $exif = @exif_read_data($file);
            if (isset($exif['Orientation'])) {
                switch ($exif['Orientation']) {
                case 1:
                    break;
                case 2:
                    $editor->filp(false, true);
                    $fixed = true;
                    break;
                case 3:
                    $editor->rotate(180);
                    $fixed = true;
                    break;
                case 4:
                    $editor->filp(true, false);
                    $fixed = true;
                    break;
                case 5:
                    $editor->rotate(270);
                    $editor->filp(false, true);
                    $fixed = true;
                    break;
                case 6:
                    $editor->rotate(270);
                    $fixed = true;
                    break;
                case 7:
                    $editor->filp(false, true);
                    $editor->rotate(90);
                    $fixed = true;
                    break;
                case 8:
                case 9:
                    $editor->rotate(90);
                    $fixed = true;
                    break;
                default:
                    $editor->rotate(0);
                    $fixed = true;
                    break;
                }
            }

            if ($fixed) $editor->save($file);
        }
    }
}

new ImageFilter();
}

動くかどうか、しばらく様子を見てみたいと思います。

最近気づいた問題点

ブログへのアクセス、特に検索が伸びないのですが、とある問題点に気づきました。

例えば、プロセッサを検索するときなど、「firewood processor」と検索していますが、これの国内の情報を得たいと思った時に、「薪 プロセッサ」で検索をしていました。が、ほとんど情報が出てこない。

ところが、これを「薪製造機」で検索すると、ガンガンヒットするわけです。

このブログの外国のメーカーや商品の記載は、基本的にその製品の原産国の母国語(の英語表記)を基本に行っているので、例えば、ヨツールではなくて、JØTUL となりますし、ハスクバーナではなく、Husqvarna となっているわけです。

今まで、全く気が付かなかったんですが、JØTUL とか、Husqvarna とか、自分は綴りを覚えてしまっていますが、初めて薪ストーブの情報を得ようとネット検索する人が正しく綴って検索するか、そういうケースで、それが適切な検索語になるのか、そう考えると、答えは NO ですね。

Screenshot 2015-02-12 11.41.17WordPress では、どういう検索語でアクセスがあったか、ある程度知ることができるので見てみたのですが、基本的に、カタカナで検索をかけてきているし、上位には、本来検索をして欲しい語が一切来ていないことに気づきます。

今後は手間ですが、カタカナ表記を併用していく、あるいは、カタカナ表記のタグを付記するなどして、検索エンジンからのアクセスを増やす工夫が必要だと感じました。

せっかく更新しても、アクセスしてもらえないと寂しいですから。

そういう意味では、Hearth & Home という屋号は最悪です。

なぜか、ということ単純明快で、Hearth という単語自体、読めない人が多い。

Hearth Stone というストーブのブランドがあるんですが、ヒースストーンとか、ハーツストーンと表記している人、ストーブを販売している人で、尊敬すべきプロフェッショナルなんですが、読めておりません。

Hearth は「暖炉」という意味で、発音は、hɑːrθ ですから、無理やりカタカナにすると、ハースです。

また、Hearth & Home という語は、温かい家庭、一家団欒という薪ストーブのある暮らしそのものを表現した素晴らしいものなのですが、その素晴らしさ故に、検索をかけると、英語のページが大量に出てきてしまうのです。

なので、屋号は、日本語で付け直す必要がありそうです。

単純にいけば、暖家とか暖談とか?

ここは、時代の流れに乗って、ポカポカ?

多分解決 — ブログ村新着記事問題

Safari のバグと、WordPress のバグと、2 つのバグが重なって発生していたブログ村に新着記事が反映されない問題ですが、おそらく解決できたと思うので、原因と対策、整理しておきたいと思います。

まず、ブログ村に新着記事が反映されない問題ですが、原因はいくつかあります。

一つは、たくさん記事を投稿しても、ブログ村の方で反映されるのは、3 件まで、という制約がある点。

この問題には、解決方法はありません。
新着記事一覧を特定のブログが占領しないようにするための制限ですから、記事の件数を減らすか、あるいは、反映されない前提で多数投稿するしかない。

次に、WordPress の仕様、というよりもバグに近い気もしますが、公開後の記事を編集すると、その都度 ping が送信され、度を越すと SPAM 扱いとなり、更新自体されなくなるという問題。

対策としては、WordPress Ping Optimizer をインストールすることで、記事の編集(修正)での ping の送信を抑制できます。
手動で送信したり、送信のログの確認もできるため、入れておくのが吉でしょう。

最後は、コンテンツに制御文字(改行を除く)が含まれると、不正な RSS が作成される問題。

対策としては、remove-control-character をというプラグインで制御文字を取り除くこと。
https://github.com/ackintosh/wp-remove-control-character

以上の対策で、今のところ、無事に新着記事が更新されています。

RSS の問題の原因か?

ブログ村に記事が更新されない問題、引き続き調べていたんですが、おそらくこれであろう、という原因を特定したので、記録しておきます。

o6asan さん、それを書いた本人です。ご迷惑をおかけして申し訳ありません。
Apple Safari 7.1 を使って書き込んだのですが、
どうやら Safari 7.1 のバグ(と思われる)により異常なデータが入ってしまったみたいです。
「を」と「丸」の間に(見えませんが)ASCIIコード 08 が1バイトだけ挟まっています。

>フォーラム管理者様
自分で編集も削除も不可能なため、お手数ですが対処して頂けないでしょうか。
どうぞよろしくお願い致します。

http://ja.forums.wordpress.org/topic/139490

このようなやりとりがあったのですが、要するに、Safari にバグがあり、0x08 の文字がブログの編集状態で紛れ込み、それによりよろしくない XML が生成される、その結果、ブログ村の方で parse error となって記事が更新されない、という流れのようです。

よって、全文ではなく、一部にしたことで、そういう制御文字が紛れ込むリスクが緩和され、更新されない頻度が低下した、というの現状と理解しました。

ブログ村の方も、parse error があったのなら、そう表示してくれればいいものを。

つまり、バグの原因としては、Safari が意図しない制御文字を含む記事を送信することと、そういう制御文字などが含まれることを意識しない WordPress が invalid な xml を吐くこと、2 つのバグが原因と思われます。

記事の登録の時点か、RSS を生成する前に食わせる記事のテキストを [cci_php]$s = preg_replace(‘/[\x00-\x09\x0b\x0c\x0e-\x1f\x7f]/’, ”, $s);[/cci_php] で済む問題だと思うのですが、はてさて、どこをどうすればいいのでしょうね。

WordPress 本体に手を入れるのはいかがかと思うので、そういうプラグインを探すなり、作るなりしたほうがよさ気。

あるいは、Safari 8 でバグが治っているのであれば、それはそれで放置してもいいかも。

ブログ村に新着記事が反映されない件 — 再発

ひところ落ち着いていた新着記事が反映されない問題ですが、このところひどくなってきたので、再度調査してみました。

ping に関しては、ログが残っており、きちんと送られている(そしてログ上は成功)ので、それ以外、つまり、ブログ村の方で spam と誤認されているとか、あるいは、RSS の問題、そのどちらかだと思うわけです。

新着記事の表示件数は、一日 3 記事に制限されていることがわかったんですが、せいぜい 2 記事程度なので、これに引っかかっているということもないわけだし、ping に関しても、記事を公開したタイミングでしか送らないので、残るは RSS だろうと当たりをつけて調べてみました。

そうすると、RSS 自体が壊れる、というか、RSS に制御コードが混じっていることが判明しました。

どういう規則で入るのかはわからないんですが、全文をフィードすると、かなり症状がひどいので、抜粋に切り替え、当該制御コードが入る部分を記事を書き換えて、制御コードが入っていないことを確認して、しばらく様子を見てみたいと思います。

RSS を作成する部分のバグ、あるいは、何かしらのプラグインの問題ではないか、と思うのですが、とりあえず、WP Multibyte Patch を切ってみました。RSS はその都度作成されるのか、それとも、記事を云々したタイミングかはわかりませんが、現状は治ったようです。

WP Multibyte Patch が悪さをしていたのかもしれません。

解決!ブログ村の新着記事トラブル

何が悪かったのかは結局わからずじまいですが、WordPress ping Optimizer を導入して、円満解決です。

精神的に良いのは、ping 結果のログが残ること。

これにより、ping が成功しているなら、それ以降の問題、送信されていないなら WordPress の側の問題と、以降は切り分けることができます。

試験的に予約投稿機能も試してみたのですが、ちゃんと ping が送信されて、ブログ村に反映されていることが確認できました。

これからは、予約投稿機能を活用して、定時更新に努めたいと思います。