'Android'에 해당되는 글 11건
- 2010.11.30 bit.ly Shorten URL 연동하기
- 2010.11.12 구글맵 주소검색 연동하기
- 2010.10.05 BMP 32/16Bit to 24Bit 변환 1
안드로이드에서 구글맵을 연동하여 어플을 개발하다보면 위/경도 좌표에 대한 주소를 알고 싶은 경우가 있다.
물론 안드로이드 기본 SDK에서 주소정보를 제공하나 그렇게 맘에 들지 않아 직접 구글맵의 주소검색 서비스를 연동하는 방식을 알아봤고, 현재 만족하게 사용을 하고 있다.
의외로 참 간단하다. HttpClient를 이용하여 연동하면 끝.
* 구글맵 주소검색 URL
http://www.google.com/maps/api/geocode/xml?latlng=37.512421,127.058815&sensor=true&language=ko
- 코엑스의 위치에 대한 한글주소를 XML 형태로 가져올 수 있다.
- latlng 파라미터는 위/경도 값이며, language는 받아보는 주소에 대한 언어 값이다. (ko=한글, en=영문 등)
- 물론 XML이 아닌 JSON이나 다른 형태도 제공한다.
- 참고로 주소에 대한 위치정보(지오코드)를 쉽고 다수로 얻으려면
http://www.biz-gis.com/bizBean/Land/Land.html 이곳이 편리하다.
* 주소검색 샘플 소스
public String searchAddressXml(double latitude, double longitude) throws Exception {
String addressXml = null;
String displayLanguage = context.getResources().getConfiguration().locale.getDisplayLanguage();
String googleUrl = "http://www.google.com/maps/api/geocode/xml?latlng=%s,%s&sensor=true&language=%s";
// 단말의 언어가 한국어로 설정되어 있으면 주소를 한글로 설정하고, 이외는 영어로 설정한다.
String language = "한국어".equals(displayLanguage) ? "ko" : "en";
googleUrl = String.format(googleUrl, String.valueOf(latitude), String.valueOf(longitude), language);
HttpClient httpClient = null;
try {
httpClient = new HttpClient();
HttpGet mGetMethod = new HttpGet(uri);
HttpResponse mHttpRes = httpClient.execute(mGetMethod);
if (mHttpRes.getStatusLine().getStatusCode() == 200) {
LineNumberReader reader = null;
try {
reader = new LineNumberReader(new InputStreamReader(mHttpRes.getEntity().getContent()));
StringBuilder httpResStr = new StringBuilder();
while ((readStr = reader.readLine()) != null) {
httpResStr.append(readStr);
}
addressXml = httpResStr.toString();
} finally {
if (reader != null) {
reader.close();
reader = null;
}
}
}
} finally {
if (httpClient != null) {
httpClient.shutdown();
httpClient = null;
}
}
return addressXml;
}
위 샘플 소스는 위/경도의 값을 받아서 주소를 검색하는 코드이여, 단말의 언어가 한국어로 되어 있으면 주소를 한글로 요청하며, 그외에는 영문으로 요청하게 된다.
코드의 결과는 XML이며, 위의 샘플 소스에 PullParser를 연결하여 분석하면 핸들링이 더욱 쉬워진다.
참 간단하지 않은가요.
안드로이드의 Bitmap은 기본적으로 16Bit(RGB_565)를 제공하며, 32Bit(ARGB_8888)을 지원한다.
그러나 이미지 처리를 위해서 Bitmap을 24Bit(RGB_888)로 변경을 해야하는 경우도 있다.
이런 경우는 기본 Android Platform에서는 지원을 하지 않고 있다. 변경이 필요하다면 소스코드에서 실제 데이터 값의 변경 작업으로 수행을 해야 하는 것 같다.
기본적으로 24Bit의 헤더 정보를 생성하야 하며, 16Bit 또는 32Bit Bitmap의 색상데이터 값에서 24Bit로 변경하는 작업을 수행해야 한다.
16Bit Bitmap : #RRRRRGGGGGGBBBBB (RGB_565)
24Bit Bitmap : #RRRRRRRRGGGGGGGGBBBBBBBB (RGB_888)
32Bit Bitmap : #AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB (ARGB_8888)
16Bit를 24Bit 또는 32Bit로의 변환은 헤더정보가 동일하며, Android에서 pixel 값을 int 형으로 추출하므로 동일하게 처리를 할 수 있다. 물론 int 형이 아닌 실 byte[]의 값으로 가져오는 것이 처리 속도면에서는 좋으나, byte에 대한 데이터형의 차이에 때문에 조금 번거로워 int 형의 픽셀값으로 처리를 한다.
* Bitmap 헤더 정보 생성
private static void encode24BMPHeader(DataOutputStream stream, int width,
int height, int fileSize) throws IOException {
// the magic number used to identify the BMP file: 0x42 0x4D
stream.writeByte(0x42);
stream.writeByte(0x4D);
stream.writeInt(swapEndian(fileSize));
// reserved
stream.writeInt(0);
// the offset, i.e. starting address of the bitmap data
stream.writeInt(swapEndian(14 + 40));
// INFORMATION HEADER (Windows V3 header) the size of this header (40 bytes)
stream.writeInt(swapEndian(40));
// the bitmap width in pixels (signed integer).
stream.writeInt(swapEndian(width));
// the bitmap height in pixels (signed integer).
stream.writeInt(swapEndian(height));
// the number of colour planes being used. Must be set to 1.
stream.writeShort(swapEndian((short) 1));
// the number of bits per pixel, which is the colour depth of the image.
stream.writeShort(swapEndian((short) 24));
// the compression method being used.
stream.writeInt(0);
// image size. The size of the raw bitmap data. 0 is valid for uncompressed.
stream.writeInt(0);
// the horizontal resolution of the image. (pixel per meter, signed integer)
stream.writeInt(0);
// the vertical resolution of the image. (pixel per meter, signed integer)
stream.writeInt(0);
// the number of colours in the colour palette, or 0 to default to 2n.
stream.writeInt(0);
// the number of important colours used, or 0 when every colour is important. generally ignored.
stream.writeInt(0);
}
실제 Bitmap의 헤더 정보에 대한 부분은 구글을 통해 손쉽게 알 수 있을 것이다.
* Bitmap 픽셀 값의 변경 (32/16Bit to 24Bit)
public static byte[] encodeBMPTo24(int[] rgb, int width, int height) throws IOException {
int padding = (4 - (width % 4)) % 4;
// the size of the BMP file in bytes
int fileSize = 14 + 40 + height * (padding + width * 3);
ByteArrayOutputStream bytes = new ByteArrayOutputStream(fileSize);
DataOutputStream out = new DataOutputStream(bytes);
// encode bitmap header (24bit over)
encode24BMPHeader(out, width, height, fileSize);
// PALETTE (none for 24 bit depth) IMAGE DATA starting in the bottom left, working right and then up
// a series of 3 bytes per pixel in the order B G R.
int colorValue = 0;
for (int j = height - 1; j >= 0; j--) {
for (int i = 0; i < width; i++) {
colorValue = rgb[i + width * j];
out.writeByte(colorValue & 0x000000FF);
out.writeByte((colorValue >>> 8) & 0x000000FF);
out.writeByte((colorValue >>> 16) & 0x000000FF);
}
// number of bytes in each row must be padded to multiple of 4
for (int i = 0; i < padding; i++) {
out.writeByte(0);
}
}
byte[] encodeBytes = bytes.toByteArray();
bytes.close();
// quick consistency check
if (encodeBytes.length != fileSize) {
throw new RuntimeException("bitmap file size bad match (32bit to 24bit)");
}
return encodeBytes;
}
위의 소스를 이용하여 실제 변경하는 소스는 아래와 같다.
public static byte[] decode24Bitmap(Bitmap bitmap) throws IOException {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int[] rgb = new int[width * height];
bitmap.getPixels(rgb, 0, width, 0, 0, width, height);
byte[] bitmap24Bytes = encodeBMPTo24(rgb, width, height);
bitmap.recycle();
bitmap = null;
rgb = null;
// system gc
//System.gc();
return bitmap24Bytes;
}