slowjet

is a part of a carburetor

パズドラ風アイコンジェネレーター ver.2 #ここでハマったよiOS

今回はiOSでハマった場所を中心にお送りします。
Android・・・?そんな(うんこ)端末知らねぇぜ・・・

パズドラ風アイコンジェネレーターはinput[type="file"]で選択した画像をFile APIを使って、読み出してCanvasに書き出してるわけですが、

その筋の人にはおそらく有名なこの問題に、例外なく遭遇しまして、事例が事例なもんで、検索しても出てこず四苦八苦してました。その中でもなにやら

  • フォトストリームに上がった写真ならOK
  • カメラを傾けて撮った写真で発生
  • どうやら写真の大きさとEXIFに問題があるようだ

というところまで、分かったところで、上のリンクを教えてもらった。

そういうわけで、このリンクを教えてもらったときにライフが限りなく0だったので、自分で実装することはせずに、stomitaさんの

を使いました。

ただまあパズドラ風アイコンジェネレーターみたいな実装にしていると、画像をCanvasに描く位置とかサイズまで指定してたりするので、ひとまずmegapixel-imagefileで、正しい画像に変換してから、その画像ソースをアイコンCanvasに渡すようにしました。

500KB超えたらnew MegaPixImageで処理する。終わったらアイコンの処理へ移動。new MegaPixImagerenderを実行してから、渡した画像オブジェクトにsrcが渡るまでには少しラグがあるので、待つようにしてる。この辺りdeferredとかイベント周りが整備されていればもうちょっと使いやすかったので、後でやってみる。

_prepareIcon: ->
  img = new Image()
  file = @model.get('file')

  # iPhoneで撮影した画像で500KBを超えているもの
  # 別途処理する、ついでにOrientationも正しい値にしておく
  if ( 500000 < parseInt(file?.size, 10) )
    new MegaPixImage(file).render(img, { maxWidth: 1280, orientation: @model.get('orientation') });

    (chk = =>
      if ( img.src )
        return @_loadImage(img.src, 'icon')
      setTimeout(chk, 100)
    )()
  else
    @_loadImage(@model.get('iconSrc'), 'icon')

途中にある、orientationは、

を使って、前もって取得してあるものを使ってます。アイコンに使う画像ファイルが選択されたら、実行されるメソッド内で取得して、modelにセットしておく。

_onChangeFile: (ev) ->
  $file = $(ev.target).closest('input')
  file = $file.get(0).files[0]

  # EXIFから正しいOrientationを取得しておく
  EXIF.getData(file, =>
    @model.set('orientation', EXIF.getTag(file, 'Orientation'))
  )

  @model.set('selected', true)
  @model.set('file', file)
  @reader.readAsDataURL(file)

ところで、orientationの値は数値になってて、何を意味してるのかさっぱり分からなかったんだけど、

このようになっているようです。

ひとまず画像がえらいちっさくなってしまうバグにも対応できて、無事リリースできました。まだちょっと既知のバグはあるのと、しょっぱなうんことか言ってしまったAndroidも保証はしないけど、ある程度までは動くようにしないとだな・・・手元の2.3でさっぱり動かない\(^o^)/

追記

そもそもAndroid2.3系はFile APIに対応してなかったのでどうしようもなかった。

関連エントリー