Smart Phone (Mobile)/Android 2011.08.12 01:09

내/외장에 저장 된 이미지 파일(PNG or JPEG ...)을 Bitmap으로 읽어 들이는 간단한 코드이다.
이미지 파일을 읽을 때 너무 큰 이미지는 OutOfMemory가 발생한다. 그래서 폰의 화면 해상도에 가장 근접하게 리스케일을 하여 읽어들이게 했다.
코드는 아주 간단하다.

/**

  * 지정한 패스의 파일을 읽어서 Bitmap 리턴 (화면사이즈에 최다한 맞춰서 리스케일한다.)

  *

  * @param context

  *            application context

  * @param imgFilePath

  *            bitmap file path

  * @return Bitmap

  * @throws IOException

  */

public static Bitmap loadBackgroundBitmap(Context context,

        String imgFilePath) throws Exception, OutOfMemoryError { 

    if (!FileUtil.exists(imgFilePath)) {

        throw new FileNotFoundException("background-image file not found : " + imgFilePath);

    }


    // 폰의 화면 사이즈를 구한다.
    Display display = ((WindowManager) context

            .getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();

    int displayWidth = display.getWidth();

    int displayHeight = display.getHeight();

 

    // 읽어들일 이미지의 사이즈를 구한다.

    BitmapFactory.Options options = new BitmapFactory.Options();

    options.inPreferredConfig = Config.RGB_565;

    options.inJustDecodeBounds = true;

    BitmapFactory.decodeFile(imgFilePath, options);

 
    // 화면 사이즈에 가장 근접하는 이미지의 리스케일 사이즈를 구한다.
    // 리스케일의 사이즈는 짝수로 지정한다. (이미지 손실을 최소화하기 위함.) 

    float widthScale = options.outWidth / displayWidth;

    float heightScale = options.outHeight / displayHeight;

    float scale = widthScale > heightScale ? widthScale : heightScale;

            

    if(scale >= 8) {

        options.inSampleSize = 8;

    } else if(scale >= 6) {

        options.inSampleSize = 6;

    } else if(scale >= 4) {

        options.inSampleSize = 4;

    } else if(scale >= 2) {

        options.inSampleSize = 2;

    } else {

        options.inSampleSize = 1;

    }

    options.inJustDecodeBounds = false;

 

    return BitmapFactory.decodeFile(imgFilePath, options);

}

저작자 표시 비영리 동일 조건 변경 허락
신고

Smart Phone (Mobile)/Android 2010.10.05 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;
}

저작자 표시 비영리 동일 조건 변경 허락
신고