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 件のコメント:

ClaudeをOpenAI O1のように思考させるDifyサンプルを試す

 Difyの「探索」タブにはさまざまなサンプルが載っており、その1つに「Thinking Claude (OpenAI O1 Alternative)」というものがある。   このサンプルがどういうものか、未だに自分でも解けない以下の問題をためしに聞いてみることにした。 『人類の...