'All Contents'에 해당되는 글 59건

  1. 2010.11.12 구글맵 주소검색 연동하기
  2. 2010.10.29 T-Store의 문제점 (주관적인 판단) 1
  3. 2010.10.05 BMP 32/16Bit to 24Bit 변환 1
Mobile Dev/Android2010. 11. 12. 13:37

안드로이드에서 구글맵을 연동하여 어플을 개발하다보면 위/경도 좌표에 대한 주소를 알고 싶은 경우가 있다.
물론 안드로이드 기본 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를 연결하여 분석하면 핸들링이 더욱 쉬워진다.
참 간단하지 않은가요.

Posted by as.wind.914


티스토어에 어플을 등록해보고 느끼는 개인적인 문제점을 적어본다.
지극히 개인적인 것일 수도 있고, 대부분의 티스터어 등록 개발자들이 공감하는 부분일 수도 있다.
티스토어 ... 물론 국내에서는 제일 활성화 된 앱스토어는 맞다. KT, LGT 모두 스토어는 있으나, 개인적으로는 있으나 마나한 스토어로 생각된다. 개발자 입장에서 어플을 등록하고 관리하는 것이 더 귀찮을 지경이다.

물론 티스토어의 좋은점도 있으나, 이 근래에 느끼는 티스토어에 대한 개인적인 생각이 이렇다.

1. 앱에 대한 검증
앱에 대한 검증은 사용자들과 개발자들에게 좋은 요소일 수도 있으나, 개인적으로는 검증 절차로 인해 개발자들이 감수해야 하는 부분들이 더 많은 것 같다.
스토어의 검증은 신청과 동시에 진행되는 것도 아니구, 얼마나의 기간이 걸릴지도 알수가 없다.
그래서 앱에 대한 등록, 업데이트에 따른 일정을 정확히 예상할 수 없으며, 이로 인해 이벤트, 프로모션 등과 같은 부분에서 굉장히 골머리를 싸매게 한다.
2. 정산
정산에 있어서 휴대폰 결재에 가장 문제인 것 같다. 유료 어플에 대한 정산을 받기 위해서도 휴대폰 결재가 대부분이기 때문에 최소 2~3개월의 기간이 걸리게 된다. 난 개인적으로 휴대폰 결재를 아주 싫어한다. ㅋㅋㅋ
물론 SKT가 휴대폰 결재를 통해 어느정도 수수료를 가져갈 수 있는 것은 인정하나, 결재 후 미납에 대한 부분을 앱 등록자 또는 개발자들이 감수해야하는 것을 좀 이해하기 힘들다.
3. 광고 또는 배너를 사용하지 못함
개발자들은 자선 사업가가 아니다. 개인의 시간을 투자해서 앱을 제작하고 등록하게 된다. 개인적으로 제작에 목적을 두고, 좋은 일을 한다고 생각하고 무료로 배포하는 것을 좋아 할 수도 있다.
그러나, 개발자들도 개인의 시간을 투자하고, 노력하여 앱을 제작하고 유료 또는 무료로 배포하게 되는데, 무료하도 최소한 광고에 의한 조그만한 수익을 기대하는 것이 잘못 된 것인가? 국내 모바일 광고 시장이 아직 빈약한 것은 사실이나 그 부분에 대한 기대는 잘못 된 것은 아니라 생각된다.
사실 앱을 티스토어 보다는 구글 스토어에 올리는 것이 개발자 입장에서는 현명하다 할 수 있다. 그러면 국내 아저씨, 아줌마들 유저는 어떻게 하나 ... ㅠㅠ
4. 국내 앱 사용자들의 마인드
국내 앱 사용자들의 마인드도 좀 문제라 생각된다. 앱에 대한 판단은 개인적이라 할 수 있지만, 앱이 무료, 싼 가격으로 책정되는 것만이 결코 좋다고 생각하면 안될 것이다. 다시 한번 말하지만 개발자들은 자선 사업가가 아니다.
조금 맘에 안든다고 악플 ... 본인의 개인적인 생각에 가격이나 기능이 맘에 들지 않는다고 악플 ... 너무하다고 생각된다.
티스토어는 당연한 것이고, 구글 스토어 가서 봐도 악플 및 쓰래기 같은 댓글은 거의 다 한글로 달려있다. 

그냥 지극히 개인적인 생각에 의해 쓴 것이지만, 티스토어는 변화가 없다면 정말 국내 일부 유저들만을 위한 마켓이 되고 말것이다. 개발자가 1개 이상의 버젼을 관리하는 것도 힘들구 ... 이제는 좀 변화가 있어야 하는 것은 아닌가 싶다.
그리고, 많은 국내형 어플을 기대한다면 사용자들의 마인드고 변화해야 한다.  

Posted by as.wind.914
Mobile Dev/Android2010. 10. 5. 16:39

안드로이드의 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;
}

Posted by as.wind.914