Translate

2011年1月6日木曜日

Androidで画像縮小する方法いろいろ

以前GridViewに画像をたくさん並べる方法
のときにサムネイル化するために
画像を縮小する必要があったのだけど、
あまり考えずに
Google App Engine で以下のようなServletを書いて
処理していた。




public class ResizeServlet extends HttpServlet {

private static final long serialVersionUID = -999999L;

/** デフォルトの高さ(ピクセル) */
public static final int HEIGHT = 50;

/** ロガー */
private static final Logger log =
Logger.getLogger(ResizeServlet.class.getName());
/**
* 生存確認
*/
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
PrintWriter pw = resp.getWriter();
pw.print("ResizeServlet is alive!");
pw.close();
}
/**
* 画像を高さ100spに変更して戻す
*/
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException{
DataInputStream dis = new DataInputStream(req.getInputStream());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int c;
while((c = dis.read())!=-1){
baos.write(c);
}
byte[] org = baos.toByteArray();
log.info("doPost: length=" + org.length);
Image image = ImagesServiceFactory.makeImage(org);
int height = image.getHeight();
int width = image.getWidth();
Transform resizer =
ImagesServiceFactory.makeResize(
(int)(((double)width*HEIGHT)/((double)height)), HEIGHT);
ImagesService service = ImagesServiceFactory.getImagesService();
byte[] result =
service.applyTransform(resizer, image).getImageData();
DataOutputStream dos = new DataOutputStream(resp.getOutputStream());
dos.write(result, 0, result.length);
dos.close();
dis.close();
}
}



App Engineの上記のServletサイトへPOSTで送った画像を
App Engineに用意されているGoogle APIで高さ100ptの画像に変換して
送信元へ返しているだけの単純なつくりだ。
実際にはパラメータで高さ指定できるものを利用しているが
サンプルコードは決め打ちにしてある。

ちなみに、Android側はURLConnectionを使ってbyte[]でもらってくればいい。
private byte[] resizeImage(String url, byte[] org) throws IOException{
 URLConnection conn = new URL(url).openConnection();
 Log.d(TAG, "getImage: url =" + url);

 conn.setDoInput(true);
 conn.setDoOutput(true);
 conn.setRequestProperty("Content-Type", "application/octet-stream");
 conn.setRequestProperty("User-Agent", "androidSample");
 conn.setRequestProperty("Content-Length", 
  new Integer(org.length).toString());

 // 送信
 OutputStream os = conn.getOutputStream();
 DataOutputStream dos = new DataOutputStream(os);
 dos.write(org, 0, org.length);

 // 受信
 InputStream is = conn.getInputStream();
 DataInputStream dis = new DataInputStream(is);
 int b;
 ByteArrayOutputStream baos = new ByteArrayOutputStream();
 while((b = dis.read())!=-1){
  baos.write(b);
 }
 dis.close();
 is.close();

 dos.close();
 os.close();

 byte[] result = baos.toByteArray();
 Log.d(TAG, "resize: org_length=" + org.length + ", result_length=" + 
  result.length);
 return result;
}


引数の変数urlは先のApp Engineの該当ServletのURLを
書けば良い。
カメラにせよ、S3上にせよ画像データをbyte[]で渡してやれば
戻り値として小さくなった画像を返してくれる。
これを非同期でGridLayoutを更新させるように実装すればいい。
#ボタンイベントなどに書くと、とたん固まってしまうから、やらないほうがいい
#とりあえず動けばいい人は書いてもいいが..


けれど、
昨日Androidの会のMLに以下のようないくつかの方法が
紹介されていた。

画像をきれいに縮小する方法

まだ試してはいないけれども
これだと通信事情が悪い場所でも
縮小できそうだ。

画像に関する知識が私にはまったくなかったので
ありもの(AppEngineのImageService)で何とかしようとしていたけど、
質問した人は画像処理について詳しい方のようで
もっといい方法を紹介してくれている。

勉強になった。

0 件のコメント:

既存アプリケーションをK8s上でコンテナ化して動かす場合の設計注意事項メモ

既存アプリをK8sなどのコンテナにして動かすには、どこを注意すればいいか..ちょっと調べたときの注意事項をメモにした。   1. The Twelve Factors (日本語訳からの転記) コードベース   バージョン管理されている1つのコードベースと複数のデプロイ 依存関係 ...