BbaDdo :: Android image crop

Android image crop

Android 2012. 9. 19. 17:18

 

퍼즐 게임에 들어가는 일부 코드 :

안드로이드 내장 갤러리를 띄워 스마트폰 sd카드에 있는 이미지나 카메라로 찍은 이미지를 불러와서 크롭(잘라내기)해서 새로운 비트맵파일을 생성하는 코드

간단한 로직이지만 스마트폰 내장 갤러리는 이미지가 새로 생성되거나 사용자가 임으로 파일을 삭제할때 그때 그때 스캔해서 이미지를 띄워주지 않는다. 

Cursor 클래스를 이용해서 Thumb nail 파일 데이터들을 같이 조작 거나 접근해서 파일들을 처리하는 로직도 있지만 일이 더 커진다... 사용자가 임으로 해당 이미지파일을 삭제하면...썸네일과 실제이미지가 꼬여버리는 일이 발생한다.  파일들을 함부로 건드리면...골치아프다는... 

하지만 한번에 이런 것들을 해결하는 코드가 미디어 재스캔

 android.content.ContextWrapper.sendBroadcast(Intent intent)
갤러리를 띄울때나 크롭할때 미디어 재스캔 요청하면 알아서 제대로 파일들을 띄워준다.

그래서 MediaStore.EXTRA_OUTPUT 를 마음 편하게 쓰면 된다.

초기화 파일 생성 및 로딩 코드도 있다. 차근 차근 보면 꽤 쓸만한 로직?

 

Main.java, main.xml, AndroidManifest.xml 세개 파일.

결과: sdcard/division 폴더속에 크롭한 이미지들이 생겨난다. 사용자가 만들어진 크롭파일들을 삭제해도 파일 이름 설정은 초기화 파일(bbaddoCrop.cfg)로 인해 계속 증가치로 저장된다. 재인스톨시 해당폴더 속에 같은 이름의 이미지가 있을시 초기화 파일이 없으므로  10000.png 로 부터 다시 덮어쓰게 됨... 파일들이 꼬여진다.. 다른 로직을 만들어 쓰면 간단히 해결된다. 아래 코드에서는 빠져있다. 

 

 

 

 

 

 

 

package pes.imagecrop;

 

 

/* 

 * Extra Options Table for image/* crop: Intent.putExtra("Options", Value of the data type);

 * 카메라 크롭을 이용해 오려진 이미지를 가져오기

 *

 * Options ""       DataType                   Description

 * =======================================================

 * crop            String                     Signals the crop feature

 * aspectX          int                        Aspect Ratio

 * aspectY          int                        Aspect Ratio

 * outputX          int                       width of output created from this Intent

 * outputY          int                       width of output created from this Intent

 * scale            boolean                    should it scale

 * return-data      boolean                 Return the bitmap with Action=inline-data by using the data

                                                crop 이미지를 intent 통해서 수신 받을 여부

 * data          Parcelable                 Bitmap to process, you may provide it a bitmap (not tested)

 * circleCrop      String                if this string is not null, it will provide some circular cr

 * output           URI              Set this URi to a File:/// , (==> MediaStore.EXTRA_OUTPUT)

                                           crop 이미지를 intent 통해서 파일로 저장. 기기마다 오류가 발생

 * noFaceDetection   boolean             camera.face

 *

 *

 */

 

import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

import java.util.Properties;

import android.app.Activity;

import android.app.AlertDialog;

import android.content.Context;

import android.content.DialogInterface;

import android.content.Intent;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.net.Uri;

import android.os.Bundle;

import android.os.Environment;

import android.provider.MediaStore;

import android.view.KeyEvent;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.ImageView;

 

 

public class Main extends Activity{

       private static final int PICK_FROM_CAMERA;  //카메라

       private static final int PICK_FROM_GALLERY;   //갤러리

       private static final int AFTER_CROP;  //크롭 com.android.camera.action.CROP

       static {

PICK_FROM_CAMERA = 0

PICK_FROM_GALLERY = 1;

AFTER_CROP = 2;

 }

       private Uri captureUri;  //카메라, 갤러리 파일 경로

       private Uri cropUri; //크롭파일 경로

       private ImageView iv;

       private Button bt;

       private int name ; //크롭파일 이름 설정 상수

       private File tempFile; //카메라 캡쳐 임시 파일

       private boolean cameraFlag = false; //임시파일 지우기 플랙, 카메라일때만 적용

      

       @Override

       public void onCreate(Bundle savedInstanceState){

             super.onCreate(savedInstanceState);

             setContentView(R.layout.main);

            

             //이미지파일 저장할 폴더 만든다

             File f = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+ "/division");

             if(!f.isDirectory()) f.mkdir();

 

             //미디어 재스캔 요청

             sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,

                                   Uri.parse("file://" + Environment.getExternalStorageDirectory())));

 

             if(!initialFileRead()){

                    name = 10000;

             }

             bt = (Button) findViewById(R.id.button);

             bt.setText("Load Images");

             iv = (ImageView) findViewById(R.id.image);

             bt.setOnClickListener(load);

       }

 

       //카메라에서 이미지 획득

       private void getCameraPhoto(){

             cameraFlag = true;

            

             //==MediaStore.ACTION_IMAGE_CAPTURE

             Intent cameraIntent = new Intent("android.media.action.IMAGE_CAPTURE");

 

             //카메라로 찍은 최초 이미지 임시파일 설정 저장

             tempFile = new File(Environment.getExternalStorageDirectory(), "tempo1234.jpg");

             captureUri = Uri.fromFile(tempFile);

            

             //==android.provider.MediaStore.EXTRA_OUTPUT == MediaStore.EXTRA_OUTPUT

             cameraIntent.putExtra("output", captureUri); //카메라 캡쳐 임시파일생성, 카메라 ok 버튼 눌렀을때

             startActivityForResult(cameraIntent, PICK_FROM_CAMERA); //0 : 카메라

       }

      

       //갤러리에서에서 이미지 획득

       private void getGalleryPhoto(){

             cameraFlag = false;

            

             //미디어 재스캔 요청

             sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,

                           Uri.parse("file://" + Environment.getExternalStorageDirectory())));

            

             // ACTION_PICK : 데이터 실제주소 이용, ACTION_GET_CONTENT : 데이터 유형 이용

             Intent galleryIntent = new Intent("android.intent.action.PICK"); // ==Intent.ACTION_PICK

            

             //==android.provider.MediaStore.Images.Media.CONTENT_TYPE

             galleryIntent.setType("vnd.android.cursor.dir/image");

            

             //이미지뷰의 이미지 선택, 두번째 파라메타가 resultCode

             startActivityForResult(galleryIntent, PICK_FROM_GALLERY);  //1 : 갤러리

       }

 

      

       //결과값 처리 : crop 해서 bitmap 생성, 원본카메라촬영 파일 제거

       @Override

       protected void onActivityResult(int requestCode, int resultCode, Intent intent) {

             //미디어 재스캔 요청

             sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,

                    Uri.parse("file://" + Environment.getExternalStorageDirectory()))); //미디어 새로 스캔

 

             //startActivityForResult(Intent, 상수)파라미터 두번째 상수값이 제대로 되었을때만 통과 -1 아닐때

             if(resultCode != RESULT_OK){  //RSULT_OK == -1

                    if (resultCode == RESULT_CANCELED){ //카메라 캔슬시 

                           if(cameraFlag){

                                 if(tempFile.exists()) tempFile.delete();

                           }

                    }

                    return;      

             }

            

             switch(requestCode) {

             case PICK_FROM_GALLERY:

                    captureUri = intent.getData();

                    crop();

                    break;

             case PICK_FROM_CAMERA:

                    crop();

                    break;

                   

             //크롭된 임시파일 제거와 View 처리를 위해 startActivityForResult 한번 호출  

             case AFTER_CROP:   

                    //저장된 크롭파일 이미지뷰에 보이기

                    try{

                        Bitmap cropPhoto = BitmapFactory.decodeFile(cropUri.getPath());

                           iv.setImageBitmap(cropPhoto);

                           iv.setScaleType(ImageView.ScaleType.FIT_XY);

                    } catch(Exception e){ return; }

 

                    //카메라 촬영 원본 임시파일 삭제

                    if(cameraFlag){

                           if(tempFile.exists()) tempFile.delete();

                    }

                    ++name;  //크롭저장파일 이름 설정

                    break;

             }

       }

 

       //이미지 크롭해서 비트맵 파일 생성

       public void crop(){

             Intent cropIntent = new Intent("com.android.camera.action.CROP"); //크롭 액티비티 실행

             //특정확장자 지정은  ex) setType("/image/jpg")

             cropIntent.setDataAndType(captureUri, "image/*"); //크롭할 파일들 경로 형식 설정

 

             //크롭파일 설정

             cropIntent.putExtra("outputX", 300);  //이미지 해상도

             cropIntent.putExtra("outputY", 300);

             cropIntent.putExtra("aspectX", 1);  //가로세로 비율

             cropIntent.putExtra("aspectY", 1);

             cropIntent.putExtra("scale", true); //꽉찬 비율로 저장

             cropIntent.putExtra("noFaceDetection", true); //camera.face

             cropIntent.putExtra("outputFormat", Bitmap.CompressFormat.PNG.toString()); //png_ 파일형식저장

          

           //생성될 크롭파일 경로 설정

           cropUri = Uri.fromFile(

                     new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/division",

                                        "c" + name + ".png"));

            

           //크롭파일 저장

           //==android.provider.MediaStore.EXTRA_OUTPUT == "output"

           cropIntent.putExtra(MediaStore.EXTRA_OUTPUT, cropUri); //크롭 파일저장

             startActivityForResult(cropIntent, AFTER_CROP);

       }

      

       //버튼 클릭이벤트

       private OnClickListener load = new OnClickListener(){

             @Override

             public void onClick(View v) {

                    new AlertDialog.Builder(Main.this)   //일단 이런식으로 얄궂게 클릭이벤트 설정

                    .setIcon(0)  //0 : 헤더아이콘 제거

                    .setTitle("Choose Image From...  ")

                    .setPositiveButton("Camera", new DialogInterface.OnClickListener(){

                           @Override

                           public void onClick(DialogInterface dialog, int which) {

                                 getCameraPhoto();

                           }

                    })

                    .setNeutralButton("Gallery", new DialogInterface.OnClickListener(){

 

                           @Override

                           public void onClick(DialogInterface dialog, int which) {

                                 getGalleryPhoto();

                           }

                    })

                    .setNegativeButton("Cancel", new DialogInterface.OnClickListener(){

 

                           @Override

                           public void onClick(DialogInterface dialog, int which) {

                                 dialog.dismiss();

                           }

                    }).show();                

             }

       };

      

      

       //===============================

       // 초기화 설정 파일 저장 불러오기

       //===============================

       public void initialFileWrite(){    //초기 설정 파일 만들기

             Properties pp = new Properties();

             pp.setProperty("name", "" + name);

      

             FileOutputStream out = null;

             try {

                    out = openFileOutput("bbaddoCrop.config", Context.MODE_PRIVATE);

                    pp.store(out,"BbaDdo Crop Config Setting");

                    out.close();

             }      catch (FileNotFoundException e) {}

                    catch (IOException e) {}

             }

                   

       public boolean initialFileRead(){  //초기 설정 파일 불러오기

             Properties pp = new Properties();

             FileInputStream in = null;

             try {

                    in = openFileInput("bbaddoCrop.config");

                    pp.load(in);

                    in.close();

             }      catch (FileNotFoundException e) {return false;}

              catch (IOException e) {return false;}

 

             name = Integer.parseInt(pp.getProperty("name"));

             return true;

       }

      

       //=========================================

       // 디바이스 BACK 이벤트 : 종료  

       //=========================================

       @Override

       public boolean onKeyUp(int keyCode, KeyEvent event) {

              if(keyCode == KeyEvent.KEYCODE_BACK){    //안드로이드 백스페이스 종료

                    new AlertDialog.Builder(this)  //프로세서 종료를 위한 얼러트다이얼로그

               .setIcon(android.R.drawable.ic_menu_close_clear_cancel)  //0 : 헤더아이콘 제거

               .setTitle("Quit")

               .setMessage("Are you sure?")

               .setPositiveButton("Yes", new DialogInterface.OnClickListener() {

                   @Override

                   public void onClick(DialogInterface dialog, int which) {

                       initialFileWrite();

                       moveTaskToBack(true);

                       finish();

                   }

               })

               .setNegativeButton("No", new DialogInterface.OnClickListener() {

                   @Override

                   public void onClick(DialogInterface dialog, int which) {

                       dialog.dismiss();

                   }

               })

               .show();

                    return true;

              }

              return super.onKeyUp(keyCode, event); 

       }

 

 

}     

 

 

 

 

 

 

===================================================================

ayout/main.xml

=================================================================== 

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent" >

 

 

       <ImageView

           android:id="@+id/image"

           android:layout_width="300dp"

           android:layout_height="300dp"

           android:layout_alignParentTop="true"

           android:layout_centerHorizontal="true"

           android:layout_marginTop="50dp"

           android:background="#555781A9" />

       <Button

           android:id="@+id/button"

           android:layout_width="wrap_content"

           android:layout_height="wrap_content"

           android:layout_alignParentBottom="true"

           android:layout_centerHorizontal="true" />

      

</RelativeLayout>

 

 

 

 

=======================================================

AndroindManifest.xml

======================================================= 

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

    package="pes.imagecrop"

    android:versionCode="1"

    android:versionName="1.0" >

 

    <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="15" />

    <uses-permission android:name="android.permission.RESTART_PACKAGES" />

       <uses-permission android:name="android.permission.CAMERA" />

       <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application

        android:icon="@drawable/ic_launcher"

        android:label="@string/app_name"

        >

        <activity

            android:name=".Main"

            android:label="@string/title_activity_main" >

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

 

                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

    </application>

 

</manifest>

 

 

 

 

 

 

 

 

 


카운터

Total : / Today : / Yesterday :
get rsstistory!