mojo's Blog
Bitmap 본문
사진과 같은 그림 파일을 안드로이드 화면에 출력할 수도 있다.
사진에 다양한 효과를 주는 방법도 지원하는데, 이를 잘 활용하면 포토샵과 비슷한 디지털 영상 처리 앱도 개발할 수 있다.
화면 중앙에 이미지 파일을 출력하는 코드를 작성해보도록 한다.
Java Code
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MyGraphicView(this));
setTitle("연습하기");
}
private static class MyGraphicView extends View{
public MyGraphicView(Context context){
super(context);
}
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
Bitmap picture = BitmapFactory.decodeResource(getResources(), R.drawable.lion);
int picX = (this.getWidth() - picture.getWidth())/2;
int picY = (this.getHeight() - picture.getHeight())/2;
canvas.drawBitmap(picture, picX, picY, null);
picture.recycle();
}
}
}
recycle() 메소드를 통해서 비트맵 리소스를 해제한다.
이미지의 기하학적 변환
안드로이드는 이미지의 기하학적 변환을 위해 이동, 확대, 축소, 회전 등의 여러 가지 메소드를 제공한다.
이미지에 대한 기하학적 변환이 아닌 캔버스에 대해 기하학적 변환을 한 후에 이미지 파일을 변환된 캔버스에 출력하는 것이다.
많이 사용되는 Canvas 클래스의 기하학적 메소드는 다음과 같다.
- 회전 : rotate()
- 확대/축소 : scale()
- 이동 : translate()
- 기울이기 : skew()
기하학적 변환 연습 Java Code
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MyGraphicView(this));
setTitle("연습하기");
}
private static class MyGraphicView extends View{
public MyGraphicView(Context context){
super(context);
}
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
Bitmap picture = BitmapFactory.decodeResource(getResources(), R.drawable.lion);
int cenX = this.getWidth()/2;
int cenY = this.getHeight()/2;
int picX = (this.getWidth() - picture.getWidth())/2;
int picY = (this.getHeight() - picture.getHeight())/2;
canvas.rotate(45, cenX,cenY);
canvas.drawBitmap(picture, picX, picY, null);
canvas.translate(-150, 200);
canvas.drawBitmap(picture,picX,picY,null);
canvas.scale(2,2,cenX,cenY);
canvas.drawBitmap(picture,picX,picY,null);
canvas.skew(0.3f, 0.3f);
canvas.drawBitmap(picture, picX, picY, null);
picture.recycle();
}
}
}
이미지 활용
포토샵 등의 이미지 처리 응용 프로그램으로 이미지에 다양한 효과를 줄 수 있다.
엠보싱, 블러링 등이 대표적이고 색상을 처리하려면 ColorMatrix 클래스를 활용한다.
블러링(blurring)은 이미지를 뿌옇게 만든다.안드로이드에서 블러링 효과를 주기 위해 BlurMaskFilter 클래스를 제공한다.블러링 클래스 생성자는 다음과 같다.
BlurMaskFilter(반지름, 스타일);
반지름은 블러링이 될 폭인데, 반지름이 클수록 이미지의 가장자리가 크게 블러링된다.
스타일에는 NORMAL, INNER, OUTER, SOLID 가 있다.
코드를 통해 스타일에 대해 어떻게 적용되는지 확인해보도록 한다.
Java Code
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MyGraphicView(this));
setTitle("연습하기");
}
private static class MyGraphicView extends View{
public MyGraphicView(Context context){
super(context);
}
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
Bitmap picture = BitmapFactory.decodeResource(getResources(), R.drawable.rabbit);
int picX = (this.getWidth() - picture.getWidth())/2;
int picY = (this.getHeight() - picture.getHeight())/2;
Paint paint = new Paint();
BlurMaskFilter bMask;
bMask = new BlurMaskFilter(30, BlurMaskFilter.Blur.INNER);
paint.setMaskFilter(bMask);
canvas.drawBitmap(picture, picX, picY, paint);
picture.recycle();
}
}
}
적용이 안되는 경우 AndroidManifest.xml 파일의 <application 안쪽에 android:hardwareAccelerated = "false" 행을 추가해야 한다.
Embossing
엠보싱(embossing)은 이미지가 블록하게 튀어나와 보이는 효과를 낸다.
엠보싱 효과를 주기 위해 안드로이드에서는 EmbossMaskFilter 클래스를 제공한다.
EmbossMaskFilter 클래스의 생성자는 블러링보다 복잡하며 형태는 다음과 같다.
EmbossMaskFilter(빛의 xyz 방향 1차 배열, 빛의 밝기, 반사 계수, 블러링 크기);
첫 번째 파라미터는 빛이 비추는 x, y, z 방향 배열이고, 두 번째 파라미터는 빛의 밝기로 0부터 1까지 지정한다.
반사 계수는 5~8 정도가 적당하다.
블러링 크기는 볼록하게 표시되기 위한 가장자리의 크기를 나타낸다.
다음은 EmbossMaskFilter에서 빛이 비추는 방향을 달리한 네 가지 효과이다.
엠보싱은 이미지를 사용하면 효과가 잘 드러나지 않아 원을 그려서 효과를 확인해본다.
Java Code
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MyGraphicView(this));
setTitle("연습하기");
}
private static class MyGraphicView extends View{
public MyGraphicView(Context context){
super(context);
}
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
int cenX = this.getWidth() / 2;
int cenY = this.getHeight() / 2;
Paint paint = new Paint();
paint.setColor(Color.GRAY);
EmbossMaskFilter eMask;
eMask = new EmbossMaskFilter(new float[]{3,3,10},0.5f,5,10);
paint.setMaskFilter(eMask);
canvas.drawCircle(cenX, cenY, 150, paint);
}
}
}
ColorMatrix
안드로이드에서는 색상이나 밝기를 조절하기 위해서 ColorMatrix 클래스와 ColorMatrixColorFilter 클래스를 사용한다.
일반적인 사용 형태는 다음과 같다.
Paint paint = new Paint();
float[] array = { 4 x 5 Array };
ColorMatrix cm = new ColorMatrix(array);
paint.setColorFilter(new ColorMatrixColorFilter(cm));
canvas.drawBitmap(~);
ColorMatrix에 사용할 배열의 각 위치 값은 다음과 같다.
Red (1) | 0 | 0 | 0 | Brightness(0) |
0 | Green(1) | 0 | 0 | Brightness(0) |
0 | 0 | Blue(1) | 0 | Brightness(0) |
0 | 0 | 0 | Alpha(1) | 0 |
기본적으로 Red, Green, Blue, Alpha 값은 1로 설정되어 있는데, 이 값을 배수로 설정하면 색상의 대비(contrast) 가 커진다.
색상의 밝기를 밝게 하기 위해서 Brightness에 양수를 입력하고 어둡게 하기 위해 음수를 입력한다.
Java Code
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MyGraphicView(this));
setTitle("연습하기");
}
private static class MyGraphicView extends View{
public MyGraphicView(Context context){
super(context);
}
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
Bitmap picture = BitmapFactory.decodeResource(getResources(), R.drawable.lion);
int picX = (this.getWidth() - picture.getWidth()) / 2;
int picY = (this.getHeight() - picture.getHeight()) / 2;
Paint paint = new Paint();
float[] array = { 2, 0, 0, 0, -25,
0, 2, 0, 0, -25,
0, 0, 2, 0, -25,
0, 0, 0, 1, 0};
ColorMatrix cm = new ColorMatrix(array);
paint.setColorFilter(new ColorMatrixColorFilter(cm));
canvas.drawBitmap(picture, picX, picY, paint);
picture.recycle();
}
}
}
연습하기 ) 미니 포토샵 앱 만들어보기
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="@+id/iconLayout"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:gravity="center"
android:padding="10dp"
android:orientation="horizontal">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="확대"
android:layout_weight="1"
android:id="@+id/btn1"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="축소"
android:layout_weight="1"
android:id="@+id/btn2"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="회전"
android:layout_weight="1"
android:id="@+id/btn3"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="밝기+"
android:layout_weight="1"
android:id="@+id/btn4"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="밝기-"
android:layout_weight="1"
android:id="@+id/btn5"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="회색"
android:layout_weight="1"
android:id="@+id/btn6"/>
</LinearLayout>
<LinearLayout
android:id="@+id/pictureLayout"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="9"
android:orientation="vertical"
android:gravity="center"/>
</LinearLayout>
Java Code
public class MainActivity extends AppCompatActivity {
Button btn1, btn2, btn3, btn4, btn5, btn6;
MyGraphicView graphicView;
static float scaleX=1, scaleY=1, angle=0, color=1, sat=1;
private void clickIcons() {
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
scaleX = scaleX + 0.2f;
scaleY = scaleY + 0.2f;
graphicView.invalidate();
}
});
btn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
scaleX = scaleX - 0.2f;
scaleY = scaleY - 0.2f;
graphicView.invalidate();
}
});
btn3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
angle += 20;
graphicView.invalidate();
}
});
btn4.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
color += 0.2f;
graphicView.invalidate();
}
});
btn5.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
color -= 0.2f;
graphicView.invalidate();
}
});
btn6.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(sat == 0) sat = 1;
else sat = 0;
graphicView.invalidate();
}
});
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setTitle("연습하기");
LinearLayout pictureLayout = (LinearLayout)findViewById(R.id.pictureLayout);
graphicView = (MyGraphicView)new MyGraphicView(this);
pictureLayout.addView(graphicView);
btn1 = (Button)findViewById(R.id.btn1);
btn2 = (Button)findViewById(R.id.btn2);
btn3 = (Button)findViewById(R.id.btn3);
btn4 = (Button)findViewById(R.id.btn4);
btn5 = (Button)findViewById(R.id.btn5);
btn6 = (Button)findViewById(R.id.btn6);
clickIcons();
}
private static class MyGraphicView extends View{
public MyGraphicView(Context context){
super(context);
}
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
Bitmap picture = BitmapFactory.decodeResource(getResources(), R.drawable.lion);
Paint paint = new Paint();
int cenX = this.getWidth() / 2;
int cenY = this.getHeight() / 2;
canvas.scale(scaleX, scaleY, cenX, cenY);
canvas.rotate(angle,cenX,cenY);
float[] array = {color, 0, 0, 0, 0,
0, color, 0, 0, 0,
0, 0, color, 0, 0,
0, 0, 0, 1, 0};
ColorMatrix cm = new ColorMatrix(array);
if(sat == 0) cm.setSaturation(sat);
paint.setColorFilter(new ColorMatrixColorFilter(cm));
int picX = (this.getWidth() - picture.getWidth()) / 2;
int picY = (this.getHeight() - picture.getHeight()) / 2;
canvas.drawBitmap(picture, picX, picY, paint);
picture.recycle();
}
}
}
버튼을 클릭하면 invalidate() 함수를 실행시켜 onDraw() 함수를 자동으로 호출하도록 한다.
회색으로 설정하는 코드를 살펴보도록 한다.
일단 채도가 1이면 기본이며, 0 ~ 1 이면 채도가 낮게 보이면 1 이상이면 채도가 높게 보인다.
채돗값을 0으로 하면 회색조 이미지가 된다.
if(sat == 0) cm.setSaturation(sat); <= 여기서 sat값이 0일때만 setSaturation을 호출하는 이유는 그 앞에 설정하였던 ColorMatrix 값이 무시되기 때문에 조건문을 달아서 채도값이 0인 경우에 setSaturation을 호출해야 한다.
'Android' 카테고리의 다른 글
액티비티와 인텐트의 기본 (0) | 2021.09.04 |
---|---|
안드로이드 프로그래밍 제 9장 연습문제 (5, 6번) (0) | 2021.09.02 |
Graphic (0) | 2021.09.02 |
안드로이드 프로그래밍 제 8장 연습문제 6번 (0) | 2021.08.31 |
파일 처리 및 응용 (0) | 2021.08.31 |