Dev Record GeoPicPlugin, GeoPicPlugin

Abstract#

画像ファイルをアップロードするときにファイルサイズを小さくしたい。

Topics#

やりたいこと#

  • GeoPicPluginでファイルサイズを抑えた写真ファイルのアップロードをしたい。ただし、本当に制限したいファイルサイズも指定したい。例えば、50Mのファイルはダメとか。

記録#

  • まずファイルの扱いをフローにしたい。
アップロードボタンが押されてから、まず、サーバにファイルがアップロードされて、そのあとEXIFを読み取るのが今回のプログラムかな。保存のタイミングはどこか。
GeoPicServlet.upload()の175ライン当たりにparseRequestというのがあり、ここで”本当に制限したいファイルサイズ”のチェックがされる。
GeoPicServlet.upload()の250ラインあたりに(FileItem)actualFileオブジェクトができている。そこから情報を吸い出しているようだ。InputStreamもそこからいつでも得られる。このInputStreamからEXIFなどを吸い出して、Fileを更新して一次フォルダに保管しておいて、ファイルアップロードを実行するときには一次保管したファイルのInputStreamを渡す。
315行あたりにthis.executeUpload(,InputStream in,)とある。
467行あたりにm_engine.getAttachmentManager().storeAttachment(att, data);とある。
AttachmentManagerの574行目にm_provider.putAttachmentData( att, in )がある。これは、WikiAttachmentProviderというInterface Classに定義されているメソッド。実態はどこだ?org.apache.wiki.providersパッケージの中にいくつかある。
この(InputStream)dataを圧縮後のファイルに置き換えるということか。
  • 一時的にファイルを保存したい。
TOMCAT_HOMEの下にtempフォルダがあって、そこにアップロードするファイルが一時的に保存されている。プロパティのworkDirを使っているところを探そう。m_engine.getWorkDir()で取れるっぽい。そこに淡々と保存するか。で、そのファイルを開いて、InputStreamをつくるか。
  • 一時ファイルの削除
もし一時ファイルに保存したとしたら、それを消すのはいつ?tempFile.deleteOnExit()
  • 画像ファイルからEXIF情報を削除するのはApache Commons Imaging[1]かな。
in は InputStream、Outは、InputStreamってできる?一度Tempファイルで保存か。サンプルを見よう[4].
  • 画像のファイルサイズの圧縮ができるAPIはあるか?
ImageIOってなんだろう[2]。いくつかサンプルが[3]。BufferredImageが便利。しかしImageオブジェクトをBufferredImageにキャストしようとしたらエラーがでた。同じ問題に当たった人も[5]
  • なんとPNGってEXIF情報保存できないんだ。。。tiffにするか。いやApache Commons Imagingでは、TIFFはEXIFに対応していないように見える[6]。そうするとPNGにして、メタデータは、書誌情報として保存か。本当にそれでいい?ImageIOを使った方法[8]をちょっと調べたうえでやろう。JPEGに越したことはない。
  • ファイル形式結論はJPEGで。
Apache Commons Imaging を使った場合。実は、JPEGの保存について、Imagingが対応していない[6]ためエラーorg.apache.commons.imaging.ImageWriteException: This image format (Jpeg-Custom) cannot be written.がでる。
	Imaging.writeImage(buffered, tempImageFile, ImageFormats.JPEG, null);
ImageIOでやるとこうなる。画質が指定できないのが玉に傷だが、シンプルだ。
	ImageIO.write(buffered, "jpeg", tempImageFile);
  • なんか写真が180度回転して表示される。どうしたものか。EXIFにあるらしい、Orientationの情報をもとに回転させたほうがいいのかな。同じ問題に当たった人も[7]。EXIFのOrientationの値をゲットすると、3とかがでてきた。これは180度回転しているものらしい[9]。graphics2Dのrotateメソッドを使おう。
  • ファイルサイズを選択するリストを最初Disableにしないと。(結局選択させないことに)
  • Reziseをチェックしないのに動いちゃった。それはまずい。(結局全部リサイズすることに)
  • ResizeをするとEXIFが消えるような気がする。当たり前なのだが。EXIF情報をコピーするとかできるのか?(結局全部消すことに)
  • ファイルをいじるところをまとめたほうがいいと思う。(一回で済ませた)
    • 回転する(EXIF次第)
    • Resizeする(必ずやる)
    • EXIFを取得する(必ずやる)
    • EXIF情報を付加する(やらないことにした)
    • EXIF情報を削除する(回転などをやるとあえてコピーしないと消える。コピーの処理はやらないことにした)
  • JPEG以外でアップロードされた場合どうするか。いまは、JPEGがPNGで保存。JPEGの時だけ動くようにしたい。(OK)
  • JPEGでもアップロードできないファイルがある。Invalid marker found in entropy dataという.ImageReadExceptionがでる。まだこれで解決するかわからないけど、Apacheでも議論があって1.0-alpha2で解決されているという[10]。2020年5月7日時点では、Mavenレポジトリから呼べないのだけど。Githubのレポジトリから最新版をクローンして、コンパイルして1.0-alpha2のJARをゲットして、JSPWikiのWEB-INFのlibフォルダに入れて解決。
  • ResizeしないとRotateされない。→もう面倒だから全部Resizeだ。
  • ん?JPEGのファイルで、全体に赤とか、黄色とかがかかる現象が。試しにPNG形式で保存しようとしても、同じ結果だ。つまり、ImageIO.writeは悪くない。getScaledInstanceを飛ばしてみても結果は同じ。ここもあまり悪くなさそう。orientationValueが3か6以外の画像も同じ現象が起きたから、graphics2D.rotateも関係なさそうだ。graphics2D.drawImage()を飛ばしても結果は変わらない。Imaging.getBufferedImage(in)が怪しい。ここで得られたBufferedImageをそのままImageIO.writeしても結果は変わらない。ここは、Imaging.getBufferedImage(in)をImageIO.read(in)に代替して、解決
  • iphoneだと90度回転がありうる。Orientation Valueとしては、6。この時、widthとheightが入れ替わることおよびその回転の中心座標に注意。
orientation value回転角度(°)高さ回転の中心座標
10widthheight回転しない
3180 degwidthheight(width/2, height/2)
690 degheightwidth(height/2, height/2)

Referece#

  1. [#1]http://commons.apache.org/proper/commons-imaging/
  2. [#2]https://qiita.com/oohira/items/be99b3c8f025d04a5541
  3. [#3]エンジニアの入り口, 2018.04.13,【入門者向け】Javaにおける画像の扱い方を分かり易く解説, https://eng-entrance.com/java-image
  4. [#4]http://commons.apache.org/proper/commons-imaging/sampleusage.html
  5. [#5]https://stackoverflow.com/questions/13605248/java-converting-image-to-bufferedimage
  6. [#6]http://commons.apache.org/proper/commons-imaging/formatsupport.html
  7. [#7]http://mumumu.github.io/blog/2013/05/15/rotate-image-depending-on-exif-orientation-value/
  8. [#8]@oohira, 2017年4月16日, JavaでJPEG画像の保存品質を変更する, https://qiita.com/oohira/items/be99b3c8f025d04a5541
  9. [#9]EXIF Tags, https://exiftool.org/TagNames/EXIF.html
  10. [#10]2019年6月9日, Invalid marker found in entropy data, https://issues.apache.org/jira/browse/IMAGING-134