[Android] 이미지 회전 또는 Mirror(반전)

작디 작은 화면을 가지는 모바일 디바이스.. 요즘은 작다고 하면 한대 맞은 시대이긴 하지만 말입니다. 여튼 모바일 디바이스에서 이미지를 참 많이 가져다 사용합니다. 아래의 코드는 파일명으로 해서 코드단에서 쉽게 사용할 수 있는 Bitmap을 하나 만드는 코드입니다.

BitmapFactory.Options bo = new BitmapFactory.Options();
bo.inSampleSize = 1;
Bitmap bmp = BitmapFactory.decodeFile(imageFilename, bo);

...

bmp.recycle(); 

와우..  참 쉽죠?  사실 1번과 2번 코드는 옵션입니다. 이 코드가 필요없을때는 BitmapFactory의 decodeFile 함수의 두번째 인자를 null로 주면 됩니다. 생성한 비트맵을 잘썼다면 7번 코드를 호출해 줍니다.

이 글의 요지는 이렇게 비트맵을 생성하는게 아니고.. 생성된 비트맵을 회전하고 Mirror시키는 방법이니다. 먼저 회전입니다.

Matrix matrix = new Matrix();
matrix.postRotate(90);
Bitmap newBmp = Bitmap.createBitmap(bmp, 0, 0, 
    bmp.getWidth(), bmp.getHeight(), matrix, true); 

2번 코드에서 postRotate 함수의 첫번째 인자가 바로 회전하고자 하는 각도입니다. 다음은 Mirror 시키는 코드입니다.

float[] mirrorY = {
    -1, 0, 0,
    0, 1, 0,
    0, 0, 1
};

Matrix matrix = new Matrix();
matrix.setValues(mirrorY);
Bitmap newBmp = Bitmap.createBitmap(bmp, 0, 0,
     bmp.getWidth(), bmp.getHeight(), matrix, true); 

회전처럼 행렬을 이동하기는 하는데.. Mirror의 경우 직접 행렬요소를 직접 지정하고 있습니다. 행렬(Matrix)는 개발자에게 매우 유용한 수학적 도구중에 하나가 분명합니다.

안드로이드에서 비트맵에 대한 이야기가 나온 차에 하나 더…! 비트맵을 파일로 저장하는 방법입니다. 안드로이드는 PNG와 JPG 포맷을 지원합니다. 아래의 코드는 비트맵을 PNG 포맷에 대한 파일로 저장하는 코드입니다.

File file = new File(filename);
FileOutputStream filestream = null;
try {
    filestream = new FileOutputStream(file);
    newBmp.compress(CompressFormat.PNG, 0, filestream);
} catch (FileNotFoundException e) {
    e.printStackTrace();
}

[Java] 파일 복사

fileName이 복사할 대상 파일이고 newFileName이 복사되어 새롭게 생성될 파일명입니다. 근데 좀 살펴볼게… 실제 데이터를 복사(전송) 시키는 12번 코드의 transfer 함수는 실제로 전송된 바이트 수를 반환합니다. 전송하고자 하는 바이트수와 실제로 전송된 바이트 수 사이에 차이가 있을 수 있다는 건데.. 이 부분에 대한 고민을 좀 더 해봐야할 코드입니다.

try {
    File inFile = new File(fileName);
    FileInputStream inputStream = new FileInputStream(inFile);
    
    File outFile = new File(newFileName);
    FileOutputStream outputStream = new FileOutputStream(outFile);
   
    FileChannel fcin = inputStream.getChannel();
    FileChannel fcout = outputStream.getChannel();
   
    long size = fcin.size();    
    fcin.transferTo(0, size, fcout);
   
    fcout.close();
    fcin.close();
    
    outputStream.close();
    inputStream.close();
} catch (Exception e) {
    e.printStackTrace();
}   

[Android] 모바일 디바이스에 저장된 전체 이미지 파일 가져오기

안드로이드를 처음 학습할때… 첨으로 별나다.. 싶었던 기억이 이었습니다만.. 지금은 제법 잘만들어진 프레임워크라는 생각이 듭니다. 버전업이 많이 되어져.. 안정화가 되었다는 것이 가장 큰 이유인듯 하지만 말입니다. 아래의 코드는 디바이스에 저장된 이미지 파일(PNG, JPG)들 전체를 얻는 코드입니다.

String[] proj = { MediaStore.Images.Media.DATA };
Cursor imageCursor = managedQuery(
    MediaStore.Images.Media.EXTERNAL_CONTENT_URI, proj, null, null, null);
   
if (imageCursor != null && imageCursor.moveToFirst()){
    String fileName;
    int dataCol = imageCursor.getColumnIndex(MediaStore.Images.Media.DATA);
    
    do {
        fileName = imageCursor.getString(dataCol);
        if (fileName != null){
            // fileName(이미지 파일명)
        }
    } while (imageCursor.moveToNext());

    imageCursor.close();
}

[ActionScript] DataGrid(Spark)의 각 셀값 읽기

var iCol:int = 0;
var rows:XMLListCollection = grid.dataProvider as XMLListCollection;
var columns:ArrayList = grid.columns as ArrayList;
var cntCols:int = columns.length;
   
for(var iRow:int=0; iRow{
    var row:Object = rows[iRow];
    
    for(iCol=0; iCol    {
        var column:GridColumn = columns.getItemAt(iCol) as GridColumn;
        var key:String = column.dataField;
        var value:String = row[key]; // Cell Value !!

        ...
    }
}

ActionScript를 통한 코드 작성이 무슨 퍼즐도 아니고…. 이리 저리 코드 조합해 나가는 재미가… 하나도 없군요… ㅡ_ㅡ; 위 코드 조합해 내느라 2시간 정도 걸렸습니다.. 나중에 또 다시 이런 시간 허비가 없도록 하기 위해 포스팅합니다..

[Java] 특정 폴더에서 원하는 확장자를 가지는 파일 목록 구하기

원하는 폴더 안에.. 특정한 확장자를 가지는 파일 목록을 얻어야 할때가 있습니다. 예를 들어서 D:/TEMP라는 폴더안에 확장자가 SHP인 파일의 목록을 배열 형태로 반환하도록 하는 경우이지요. 이때 사용할만한 함수입니다.

private Vector getFileNames(String targetDirName, String fileExt) {
    Vector fileNames = new Vector();
    File dir = new File(targetDirName);
    fileExt = fileExt.toLowerCase();
  
    if(dir.isDirectory()) {
        String dirName = dir.getPath();
        String[] filenames = dir.list(null);
        int cntFiles = filenames.length;
       
        for(int iFile=0; iFile            String filename = filenames[iFile];
            String fullFileName = dirName + "/" + filename;
            File file = new File(fullFileName);
 
            boolean isDirectory = file.isDirectory();
            if(!isDirectory && filename.toLowerCase().endsWith(fileExt)) {
                fileNames.add(fullFileName);
            }
        }
    }

    return fileNames;
 }

제가 이 함수가 필요했던 이유는.. 특정 폴더에 존재하는 수백개의 항공영상이나 수백개의 SHP 파일을 한꺼번에 레이어로 추가하고자 하는 필요 때문이였습니다.

아래의 코드는 안드로이드 기반의 GIS 엔진인 블랙포인트에서 위의 함수를 사용해 25cm 해상도의 192개의 항공영상(GEOTIFF 기준으로 40GB 이상)과 일정한 격자로 나눈  SHP 파일 185개(전체 용량 85MB)를 올리는 코드예입니다.

LayerManager layerMan = map.getLayerManager();
  
String ess = Environment.getExternalStorageState();   
String sdCardPath = null;   
if(ess.equals(Environment.MEDIA_MOUNTED)) {   
    sdCardPath = Environment.getExternalStorageDirectory().getAbsolutePath();
    String rootDir = sdCardPath + "/mapdata/yp";
    
    // 항공사진 레이어 추가  
    Vector xrrFiles = getFileNames(rootDir +"/XrR", "xrr");
    for(int i=0; i        ILayer layer = new TileImageLayer("xrr_" + i, xrrFiles.get(i), false);
        layerMan.addLayer(layer);
    }

    // 수치지도 레이어 추가
    Vector cassFiles = getFileNames(rootDir + "/CBND", "shp");
    int cntCbndLyr = cassFiles.size();
    for(int i=0; i        ILayer layer = new ShapeLayer("cbnd_" + i, cassFiles.get(i));
        layerMan.addLayer(layer);
       
        ShapeLayerLabel roadLbl = (ShapeLayerLabel)shpLyr.getLabel();
        roadLbl.setFieldName("JIBUN");
        roadLbl.setEnable(true);
        roadLbl.getFontSymbol().setTextSize(11);
        SimpleDrawShapeTheme roadTheme = (SimpleDrawShapeTheme)shpLyr.getTheme();
        roadTheme.getFillSymbol().setHollow(true);
        roadLbl.getFontSymbol().setTextColor(Color.GREEN);
        roadTheme.getStrokeSymbol().setColor(Color.YELLOW);
}

아래는 위의 코드에 반영된 시스템에 대한 실행 화면입니다. 클릭하면 원본 크기로 볼 수 있습니다.