private File[] getJpgFiles(File f){
File[] files = f.listFiles(new FilenameFilter(){
@Override
public boolean accept(File dir, String filename) {
return filename.toLowerCase().endsWith(".jpg");
}});
return files;
}
Friday, August 30, 2013
List files in directory with specified type
The example List all 'jpg' files in given directoty:
Get bitmap color on touched position in ImageView
Last exercise demonstrate "How to detect touch event and position on ImageView". It's modified to get bitmap color on the touched position.
Modify android:scaleType and android:adjustViewBounds of ImageView in activity_main.xml. You can also try different setting to see how it affect the ImageView and Bitmap reloation.
Download the files.
Next: Detect touch and free draw on Bitmap
more: Something about processing images in Android
package com.example.androiddrawbitmap;
import java.io.FileNotFoundException;
import android.R.color;
import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
public class MainActivity extends Activity {
Button btnLoadImage;
TextView textSource, textInfo;
ImageView imageResult;
final int RQS_IMAGE1 = 1;
Uri source;
Bitmap bitmapMaster;
Canvas canvasMaster;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnLoadImage = (Button)findViewById(R.id.loadimage);
textSource = (TextView)findViewById(R.id.sourceuri);
imageResult = (ImageView)findViewById(R.id.result);
btnLoadImage.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0) {
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, RQS_IMAGE1);
}});
imageResult.setOnTouchListener(new OnTouchListener(){
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
int x = (int) event.getX();
int y = (int) event.getY();
switch(action){
case MotionEvent.ACTION_DOWN:
textSource.setText("ACTION_DOWN- " + x + " : " + y);
textSource.setBackgroundColor(
getProjectedColor((ImageView)v, bitmapMaster, x, y));
break;
case MotionEvent.ACTION_MOVE:
textSource.setText("ACTION_MOVE- " + x + " : " + y);
textSource.setBackgroundColor(
getProjectedColor((ImageView)v, bitmapMaster, x, y));
break;
case MotionEvent.ACTION_UP:
textSource.setText("ACTION_UP- " + x + " : " + y);
textSource.setBackgroundColor(
getProjectedColor((ImageView)v, bitmapMaster, x, y));
break;
}
/*
* Return 'true' to indicate that the event have been consumed.
* If auto-generated 'false', your code can detect ACTION_DOWN only,
* cannot detect ACTION_MOVE and ACTION_UP.
*/
return true;
}});
}
/*
* Project position on ImageView to position on Bitmap
* return the color on the position
*/
private int getProjectedColor(ImageView iv, Bitmap bm, int x, int y){
if(x<0 || y<0 || x > iv.getWidth() || y > iv.getHeight()){
//outside ImageView
return color.background_light;
}else{
int projectedX = (int)((double)x * ((double)bm.getWidth()/(double)iv.getWidth()));
int projectedY = (int)((double)y * ((double)bm.getHeight()/(double)iv.getHeight()));
textSource.setText(x + ":" + y + "/" + iv.getWidth() + " : " + iv.getHeight() + "\n" +
projectedX + " : " + projectedY + "/" + bm.getWidth() + " : " + bm.getHeight()
);
return bm.getPixel(projectedX, projectedY);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK){
switch (requestCode){
case RQS_IMAGE1:
source = data.getData();
textSource.setText(source.toString());
try {
bitmapMaster = BitmapFactory.decodeStream(
getContentResolver().openInputStream(source));
imageResult.setImageBitmap(bitmapMaster);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
}
}
}
Modify android:scaleType and android:adjustViewBounds of ImageView in activity_main.xml. You can also try different setting to see how it affect the ImageView and Bitmap reloation.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold" />
<Button
android:id="@+id/loadimage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Load Image 1" />
<TextView
android:id="@+id/sourceuri"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<ImageView
android:id="@+id/result"
android:scaleType="centerInside"
android:adjustViewBounds="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/background_dark" />
</LinearLayout>
Download the files.
Next: Detect touch and free draw on Bitmap
more: Something about processing images in Android
Thursday, August 29, 2013
Detect touch on ImageView
The example demonstrate how to detect touch event and position on ImageView, by implementing OnTouchListener().
MainActivity.java
Layout
Download the files.
Next: Get bitmap color on touched position in ImageView
more: Something about processing images in Android
MainActivity.java
package com.example.androiddrawbitmap;
import java.io.FileNotFoundException;
import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
public class MainActivity extends Activity {
Button btnLoadImage;
TextView textSource, textInfo;
ImageView imageResult;
final int RQS_IMAGE1 = 1;
Uri source;
Bitmap bitmapMaster;
Canvas canvasMaster;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnLoadImage = (Button)findViewById(R.id.loadimage);
textSource = (TextView)findViewById(R.id.sourceuri);
imageResult = (ImageView)findViewById(R.id.result);
btnLoadImage.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0) {
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, RQS_IMAGE1);
}});
imageResult.setOnTouchListener(new OnTouchListener(){
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
int x = (int) event.getX();
int y = (int) event.getY();
switch(action){
case MotionEvent.ACTION_DOWN:
textSource.setText("ACTION_DOWN- " + x + " : " + y);
break;
case MotionEvent.ACTION_MOVE:
textSource.setText("ACTION_MOVE- " + x + " : " + y);
break;
case MotionEvent.ACTION_UP:
textSource.setText("ACTION_UP- " + x + " : " + y);
break;
}
/*
* Return 'true' to indicate that the event have been consumed.
* If auto-generated 'false', your code can detect ACTION_DOWN only,
* cannot detect ACTION_MOVE and ACTION_UP.
*/
return true;
}});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK){
switch (requestCode){
case RQS_IMAGE1:
source = data.getData();
textSource.setText(source.toString());
try {
bitmapMaster = BitmapFactory.decodeStream(
getContentResolver().openInputStream(source));
imageResult.setImageBitmap(bitmapMaster);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
}
}
}
Layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold" />
<Button
android:id="@+id/loadimage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Load Image 1" />
<TextView
android:id="@+id/sourceuri"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<ImageView
android:id="@+id/result"
android:scaleType="matrix"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/background_dark" />
</LinearLayout>
Download the files.
Next: Get bitmap color on touched position in ImageView
more: Something about processing images in Android
Tuesday, August 27, 2013
Android Native Development Kit Cookbook
Android Native Development Kit Cookbook
A step-by-step tutorial with more than 60 concise recipes on Android NDK development skills
Overview
- Build, debug, and profile Android NDK apps
- Implement part of Android apps in native C/C++ code.
- Optimize code performance in assembly with Android NDK.
In Detail
Building Android applications would usually mean that you spend all of your time working in Java. There are however times when this is not the most efficient or best method for the application being built. This is where Android NDK comes in. Android NDK allows the developer to write in Native C/C++, giving you the power to reuse code and libraries and also, in most cases, increase the speed and efficiency of your application.
The "Android Native Development Kit Cookbook" will help you understand the development, building, and debugging of your native Android applications. We will discover and learn JNI programming and essential NDK APIs such as OpenGL ES, and the native application API. We will then explore the process of porting existing libraries and software to NDK. By the end of this book you will be able to build your own apps in NDK apps.
"Android Native Development Kit Cookbook" begins with basic recipes that will help you in the building and debugging of native apps, and JNI programming. The recipes cover various topics of application development with Android NDK such as OpenGL programming and Multimedia programming. We will begin with a simple recipe, Hello NDK, before moving on to cover advanced topics with recipes on OpenGL ES that focus on 2D and 3D graphics, as well as recipes that discuss working with NDK and external APIs. If you are looking for ways to make your application available in Android and take measures to boost your application’s performance, then this Cookbook is for you.
What you will learn from this book
- Develop Android apps in C/C++ without a single line of Java.
- Program 2D/3D graphics with both OpenGL ES 1x and 2.0 in Android NDK.
- Write multi-threaded Android apps in Android NDK.
- Port existing C/C++ libraries and applications to Android with NDK.
- Develop multimedia Android apps with Android NDK.
Approach
This book is written in a Cookbook style, beginning with recipes which focus on helping developers make their software/application available in Android.
Who this book is written for
Android developers who want to learn Android NDK programming, or develop multimedia and games in Android NDK will benefit from this book.
Fine tune scaled down bitmap to exact size
Last post genarate a scaled down bitmaps, approximate but not exact size. In order to fine tune bitmap to exact size, we can re-create another bitmap from this scaled bitmap using Bitmap.createScaledBitmap() method with expected width and height.
Modify MainActivity.java from Last post to fine tune bitmap after scaled.
Download the files.
more: Something about processing images in Android
Modify MainActivity.java from Last post to fine tune bitmap after scaled.
package com.test.androidimageprocessing;
import java.io.FileNotFoundException;
import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import com.example.androidimageprocessing.R;
public class MainActivity extends Activity {
Button btnLoadImage1, btnLoadImage2;
TextView textSource1, textSource2;
Button btnProcessing;
ImageView imageResult;
Spinner spinnerMode;
final int RQS_IMAGE1 = 1;
final int RQS_IMAGE2 = 2;
Uri source1, source2;
String[] arrayModeName = { "ADD", "CLEAR", "DARKEN", "DST", "DST_ATOP",
"DST_IN", "DST_OUT", "DST_OVER", "LIGHTEN", "MULTIPLY", "OVERLAY",
"SCREEN", "SRC", "SRC_ATOP", "SRC_IN", "SRC_OUT", "SRC_OVER", "XOR" };
/*
* To use Mode.ADD and Mode.OVERLAY, android:minSdkVersion have to be set
* "11" or higher.
*/
PorterDuff.Mode[] arrayMode = { Mode.ADD, Mode.CLEAR, Mode.DARKEN,
Mode.DST, Mode.DST_ATOP, Mode.DST_IN, Mode.DST_OUT, Mode.DST_OVER,
Mode.LIGHTEN, Mode.MULTIPLY, Mode.OVERLAY, Mode.SCREEN, Mode.SRC,
Mode.SRC_ATOP, Mode.SRC_IN, Mode.SRC_OUT, Mode.SRC_OVER, Mode.XOR };
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnLoadImage1 = (Button) findViewById(R.id.loadimage1);
btnLoadImage2 = (Button) findViewById(R.id.loadimage2);
textSource1 = (TextView) findViewById(R.id.sourceuri1);
textSource2 = (TextView) findViewById(R.id.sourceuri2);
btnProcessing = (Button) findViewById(R.id.processing);
imageResult = (ImageView) findViewById(R.id.result);
spinnerMode = (Spinner) findViewById(R.id.mode);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(
MainActivity.this, android.R.layout.simple_spinner_item,
arrayModeName);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinnerMode.setAdapter(adapter);
btnLoadImage1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
Intent intent = new Intent(
Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, RQS_IMAGE1);
}
});
btnLoadImage2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
Intent intent = new Intent(
Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, RQS_IMAGE2);
}
});
btnProcessing.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (source1 != null && source2 != null) {
Bitmap processedBitmap = ProcessingBitmap();
if (processedBitmap != null) {
imageResult.setImageBitmap(processedBitmap);
Toast.makeText(getApplicationContext(), "Done",
Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getApplicationContext(),
"Something wrong in processing!",
Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(getApplicationContext(),
"Select both image!", Toast.LENGTH_LONG).show();
}
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
switch (requestCode) {
case RQS_IMAGE1:
source1 = data.getData();
textSource1.setText(source1.toString());
break;
case RQS_IMAGE2:
source2 = data.getData();
textSource2.setText(source2.toString());
break;
}
}
}
private Bitmap ProcessingBitmap() {
Bitmap bm1 = null;
Bitmap bm2 = null;
Bitmap newBitmap = null;
try {
/*
* bm1 = BitmapFactory.decodeStream(getContentResolver()
* .openInputStream(source1));
* bm2 = BitmapFactory.decodeStream(getContentResolver()
* .openInputStream(source2));
*/
bm1 = loadScaledBitmap(source1);
Toast.makeText(getApplicationContext(),
"bm1: " + bm1.getWidth() + " x " + bm1.getHeight(),
Toast.LENGTH_LONG).show();
bm2 = loadScaledBitmap(source2);
Toast.makeText(getApplicationContext(),
"bm2: " + bm2.getWidth() + " x " + bm2.getHeight(),
Toast.LENGTH_LONG).show();
int w;
if (bm1.getWidth() >= bm2.getWidth()) {
w = bm1.getWidth();
} else {
w = bm2.getWidth();
}
int h;
if (bm1.getHeight() >= bm2.getHeight()) {
h = bm1.getHeight();
} else {
h = bm2.getHeight();
}
Config config = bm1.getConfig();
if (config == null) {
config = Bitmap.Config.ARGB_8888;
}
newBitmap = Bitmap.createBitmap(w, h, config);
Canvas newCanvas = new Canvas(newBitmap);
newCanvas.drawBitmap(bm1, 0, 0, null);
Paint paint = new Paint();
int selectedPos = spinnerMode.getSelectedItemPosition();
PorterDuff.Mode selectedMode = arrayMode[selectedPos];
paint.setXfermode(new PorterDuffXfermode(selectedMode));
newCanvas.drawBitmap(bm2, 0, 0, paint);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return newBitmap;
}
private Bitmap loadScaledBitmap(Uri src) throws FileNotFoundException {
// required max width/height
final int REQ_WIDTH = 1024;
final int REQ_HEIGHT = 1024;
Bitmap bm = null;
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(getContentResolver().openInputStream(src),
null, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, REQ_WIDTH,
REQ_HEIGHT);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
bm = BitmapFactory.decodeStream(
getContentResolver().openInputStream(src), null, options);
/*
* Up to here, bm will be scaled down, but not exactly expected size!
*
* To fine tune the size, re-create another bitmap from this scaled bitmap
* using Bitmap.createScaledBitmap() method with expected width and height.
*/
final int LONGEST_LENGTH = 1024;
int dstWidth, dstHeight;
if(options.outWidth >= options.outHeight){
//Landscape orientation
dstWidth = LONGEST_LENGTH;
dstHeight = LONGEST_LENGTH * options.outHeight/options.outWidth;
}else{
//portrait orientation
dstHeight = LONGEST_LENGTH;
dstWidth = LONGEST_LENGTH * options.outWidth/options.outHeight;
}
//To save memory, re-use bm
bm = Bitmap.createScaledBitmap(bm, dstWidth, dstHeight, false);
return bm;
}
private int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
// Calculate ratios of height and width to requested height and
// width
final int heightRatio = Math.round((float) height
/ (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will
// guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
Toast.makeText(getApplicationContext(),
"inSampleSize: " + inSampleSize, Toast.LENGTH_LONG).show();
return inSampleSize;
}
}
Download the files.
more: Something about processing images in Android
Monday, August 26, 2013
Load scaled bitmap
Last post provide UN-RECOMMENDED methods to handle error of 'OutOfMemoryError' and 'Bitmap too large to be uploaded into a texture' for images/bitmaps. Here is another approach, scale-down bitmap before processing and display. It's recommanded by Google's document Loading Large Bitmaps Efficiently for displaying bitmap.
Please note that the final value of BitmapFactory.Options.inSampleSize used by decoder will be based on powers of 2, any other value will be rounded down to the nearest power of 2.
For example: if the original photos is in 4256x2832, and REQ_WIDTH/REQ_HEIGHT are 1024, the calculated inSampleSize will be 3. But the rounded down value used by decoder will be 2. And the scaled bitmap will be 2128x1416.
Refer to the exercise "Merge images with PorterDuffXfermode", modify MainActivity.java to implement loadScaledBitmap() and calculateInSampleSize() methods.
Download the files.
Next: Fine tune scaled down bitmap to exact size
Related: Scale bitmap with inDither and inPreferQualityOverSpeed
more: Something about processing images in Android
Please note that the final value of BitmapFactory.Options.inSampleSize used by decoder will be based on powers of 2, any other value will be rounded down to the nearest power of 2.
For example: if the original photos is in 4256x2832, and REQ_WIDTH/REQ_HEIGHT are 1024, the calculated inSampleSize will be 3. But the rounded down value used by decoder will be 2. And the scaled bitmap will be 2128x1416.
Refer to the exercise "Merge images with PorterDuffXfermode", modify MainActivity.java to implement loadScaledBitmap() and calculateInSampleSize() methods.
package com.test.androidimageprocessing;
import java.io.FileNotFoundException;
import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import com.example.androidimageprocessing.R;
public class MainActivity extends Activity {
Button btnLoadImage1, btnLoadImage2;
TextView textSource1, textSource2;
Button btnProcessing;
ImageView imageResult;
Spinner spinnerMode;
final int RQS_IMAGE1 = 1;
final int RQS_IMAGE2 = 2;
Uri source1, source2;
String[] arrayModeName = { "ADD", "CLEAR", "DARKEN", "DST", "DST_ATOP",
"DST_IN", "DST_OUT", "DST_OVER", "LIGHTEN", "MULTIPLY", "OVERLAY",
"SCREEN", "SRC", "SRC_ATOP", "SRC_IN", "SRC_OUT", "SRC_OVER", "XOR" };
/*
* To use Mode.ADD and Mode.OVERLAY, android:minSdkVersion have to be set
* "11" or higher.
*/
PorterDuff.Mode[] arrayMode = { Mode.ADD, Mode.CLEAR, Mode.DARKEN,
Mode.DST, Mode.DST_ATOP, Mode.DST_IN, Mode.DST_OUT, Mode.DST_OVER,
Mode.LIGHTEN, Mode.MULTIPLY, Mode.OVERLAY, Mode.SCREEN, Mode.SRC,
Mode.SRC_ATOP, Mode.SRC_IN, Mode.SRC_OUT, Mode.SRC_OVER, Mode.XOR };
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnLoadImage1 = (Button) findViewById(R.id.loadimage1);
btnLoadImage2 = (Button) findViewById(R.id.loadimage2);
textSource1 = (TextView) findViewById(R.id.sourceuri1);
textSource2 = (TextView) findViewById(R.id.sourceuri2);
btnProcessing = (Button) findViewById(R.id.processing);
imageResult = (ImageView) findViewById(R.id.result);
spinnerMode = (Spinner) findViewById(R.id.mode);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(
MainActivity.this, android.R.layout.simple_spinner_item,
arrayModeName);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinnerMode.setAdapter(adapter);
btnLoadImage1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
Intent intent = new Intent(
Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, RQS_IMAGE1);
}
});
btnLoadImage2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
Intent intent = new Intent(
Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, RQS_IMAGE2);
}
});
btnProcessing.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (source1 != null && source2 != null) {
Bitmap processedBitmap = ProcessingBitmap();
if (processedBitmap != null) {
imageResult.setImageBitmap(processedBitmap);
Toast.makeText(getApplicationContext(), "Done",
Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getApplicationContext(),
"Something wrong in processing!",
Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(getApplicationContext(),
"Select both image!", Toast.LENGTH_LONG).show();
}
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
switch (requestCode) {
case RQS_IMAGE1:
source1 = data.getData();
textSource1.setText(source1.toString());
break;
case RQS_IMAGE2:
source2 = data.getData();
textSource2.setText(source2.toString());
break;
}
}
}
private Bitmap ProcessingBitmap() {
Bitmap bm1 = null;
Bitmap bm2 = null;
Bitmap newBitmap = null;
try {
/*
* bm1 = BitmapFactory.decodeStream(getContentResolver()
* .openInputStream(source1)); bm2 =
* BitmapFactory.decodeStream(getContentResolver()
* .openInputStream(source2));
*/
bm1 = loadScaledBitmap(source1);
Toast.makeText(getApplicationContext(),
"bm1: " + bm1.getWidth() + " x " + bm1.getHeight(),
Toast.LENGTH_LONG).show();
bm2 = loadScaledBitmap(source2);
Toast.makeText(getApplicationContext(),
"bm2: " + bm2.getWidth() + " x " + bm2.getHeight(),
Toast.LENGTH_LONG).show();
int w;
if (bm1.getWidth() >= bm2.getWidth()) {
w = bm1.getWidth();
} else {
w = bm2.getWidth();
}
int h;
if (bm1.getHeight() >= bm2.getHeight()) {
h = bm1.getHeight();
} else {
h = bm2.getHeight();
}
Config config = bm1.getConfig();
if (config == null) {
config = Bitmap.Config.ARGB_8888;
}
newBitmap = Bitmap.createBitmap(w, h, config);
Canvas newCanvas = new Canvas(newBitmap);
newCanvas.drawBitmap(bm1, 0, 0, null);
Paint paint = new Paint();
int selectedPos = spinnerMode.getSelectedItemPosition();
PorterDuff.Mode selectedMode = arrayMode[selectedPos];
paint.setXfermode(new PorterDuffXfermode(selectedMode));
newCanvas.drawBitmap(bm2, 0, 0, paint);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return newBitmap;
}
private Bitmap loadScaledBitmap(Uri src) throws FileNotFoundException {
// required max width/height
final int REQ_WIDTH = 800;
final int REQ_HEIGHT = 800;
Bitmap bm = null;
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(getContentResolver().openInputStream(src),
null, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, REQ_WIDTH,
REQ_HEIGHT);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
bm = BitmapFactory.decodeStream(
getContentResolver().openInputStream(src), null, options);
return bm;
}
public int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
// Calculate ratios of height and width to requested height and
// width
final int heightRatio = Math.round((float) height
/ (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will
// guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
Toast.makeText(getApplicationContext(),
"inSampleSize: " + inSampleSize, Toast.LENGTH_LONG).show();
return inSampleSize;
}
}
Download the files.
Next: Fine tune scaled down bitmap to exact size
Related: Scale bitmap with inDither and inPreferQualityOverSpeed
more: Something about processing images in Android
Sunday, August 25, 2013
Handle error of 'OutOfMemoryError' and 'Bitmap too large to be uploaded into a texture' for images/bitmaps
Before start this post, I have to mention that: IT'S STRONGLY NOT RECOMMENDED TO USE THE APPROACH HERE.
In the previous exercise for image processing, I haven't handle resizing of the images/bitmaps. It will cause the app close, or no display on ImageView, if you try to load with large images. Mainly there are two problem here:
- java.lang.OutOfMemoryError
It's due to Heap Size not enough to handle the bitmaps, you can try to require large heap by defining android:largeHeap="true" inside <application> in AndroidManifest.xml file. In my trial experience, after defined it, the app can handle the original 3264x2448 photos taken by HTC One X, but cannot handle original 4256x2832 photos from Nikon D700 DSLR.
- Bitmap too large to be uploaded into a texture (..., max=2048x2048)
It's due to OpenGLRenderer hardware Acceleration cannot handle bitmap larger than 2048x2048. You can try to disable hardware Acceleration by defining android:hardwareAccelerated="false" inside <application> in AndroidManifest.xml file.
Finally, your AndroidManifest.xml will look like this:
Exercise of "Merge images with PorterDuffXfermode" with these modification to handle original photos by HTC One X.
Anyway, both method cannot solve the problem perfectly, so it's not recommended.
Sometimes, even you have enough memory but not in single block. For example, you have three 1K memory block in seperated area, but you request memory of 1.5K, you will get 'OutOfMemoryError' also!
Good official lessons teach Caching Bitmaps and Managing Bitmap Memory, it is recommended to read if you need to handle a number of images in your app.
more: Something about processing images in Android
In the previous exercise for image processing, I haven't handle resizing of the images/bitmaps. It will cause the app close, or no display on ImageView, if you try to load with large images. Mainly there are two problem here:
- java.lang.OutOfMemoryError
It's due to Heap Size not enough to handle the bitmaps, you can try to require large heap by defining android:largeHeap="true" inside <application> in AndroidManifest.xml file. In my trial experience, after defined it, the app can handle the original 3264x2448 photos taken by HTC One X, but cannot handle original 4256x2832 photos from Nikon D700 DSLR.
- Bitmap too large to be uploaded into a texture (..., max=2048x2048)
It's due to OpenGLRenderer hardware Acceleration cannot handle bitmap larger than 2048x2048. You can try to disable hardware Acceleration by defining android:hardwareAccelerated="false" inside <application> in AndroidManifest.xml file.
Finally, your AndroidManifest.xml will look like this:
<application
...
android:hardwareAccelerated="false"
android:largeHeap="true" >
Exercise of "Merge images with PorterDuffXfermode" with these modification to handle original photos by HTC One X.
Anyway, both method cannot solve the problem perfectly, so it's not recommended.
Sometimes, even you have enough memory but not in single block. For example, you have three 1K memory block in seperated area, but you request memory of 1.5K, you will get 'OutOfMemoryError' also!
Good official lessons teach Caching Bitmaps and Managing Bitmap Memory, it is recommended to read if you need to handle a number of images in your app.
more: Something about processing images in Android
Saturday, August 24, 2013
Google Play Developer Program Policy Update
As of August 23, 2013, the new Google Play Developer Program Policy (“Content Policy”) will be in effect for all new applications submitted to the service. Any pre-existing applications must achieve compliance or be voluntarily unpublished by the developer within 30 days of the issuance of this notification.
https://support.google.com/googleplay/android-developer/answer/3311168
The Google Play Developer Program Policy (“Content Policy”) have been updated. Improvements include new guidance on ads behavior and clarifications to existing policies related to hate speech, gambling, in-app payments, ratings, and impersonation.
Please visit and familiarize yourself with the above policies. If you find any existing applications in your catalog to be in non-compliance, we ask you to remedy and republish the application within 30 calendar days of the posting of this notification. After this time period, applications discovered to be in violation may be subject to removal from Google Play. Any newly published applications must adhere to the latest version of the Content Policy for Google Play.
https://support.google.com/googleplay/android-developer/answer/3311168
The Google Play Developer Program Policy (“Content Policy”) have been updated. Improvements include new guidance on ads behavior and clarifications to existing policies related to hate speech, gambling, in-app payments, ratings, and impersonation.
Please visit and familiarize yourself with the above policies. If you find any existing applications in your catalog to be in non-compliance, we ask you to remedy and republish the application within 30 calendar days of the posting of this notification. After this time period, applications discovered to be in violation may be subject to removal from Google Play. Any newly published applications must adhere to the latest version of the Content Policy for Google Play.
Friday, August 23, 2013
Share bitmap between Activities
This exercise demonstrate how to using static Bitmap in a common class in application, to share between activities. Such that, no need to pass between activities.
CommonBitmap.java, it simple hold a static Bitmap. It can be accessed by all activities in application, using CommonBitmap.bitmap.
MainActivity.java
activity_main.xml
Activity2.java, code of the second activity.
activity2_layout.xml
Finally, add the second activity Activity2.java to AndroidManifest.xml.
Download the files.
more: Something about processing images in Android
CommonBitmap.java, it simple hold a static Bitmap. It can be accessed by all activities in application, using CommonBitmap.bitmap.
package com.example.androidcommonbitmap;
import android.graphics.Bitmap;
public class CommonBitmap {
public static Bitmap bitmap = null;
}
MainActivity.java
package com.example.androidcommonbitmap;
import java.io.FileNotFoundException;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.app.Activity;
import android.content.Intent;
import android.graphics.BitmapFactory;
public class MainActivity extends Activity {
Button btnLoadImage1;
TextView textSource1;
Button btnStartActivity;
ImageView imageResult;
final int RQS_LOADIMAGE = 1;
final int RQS_ACTIVITY2 = 2;
Uri source1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnLoadImage1 = (Button)findViewById(R.id.loadimage1);
textSource1 = (TextView)findViewById(R.id.sourceuri1);
btnStartActivity = (Button)findViewById(R.id.startactivity);
imageResult = (ImageView)findViewById(R.id.result);
btnLoadImage1.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0) {
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, RQS_LOADIMAGE);
}});
btnStartActivity.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0) {
Intent intent = new Intent(MainActivity.this, Activity2.class);
startActivityForResult(intent, RQS_ACTIVITY2);
}});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK){
switch (requestCode){
case RQS_LOADIMAGE:
source1 = data.getData();
textSource1.setText(source1.toString());
try {
//save common static bitmap
CommonBitmap.bitmap = BitmapFactory.decodeStream(
getContentResolver().openInputStream(source1));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
case RQS_ACTIVITY2:
imageResult.setImageBitmap(CommonBitmap.bitmap);
break;
}
}
}
}
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".MainActivity" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold"
android:layout_gravity="center_horizontal"
android:autoLink="web" />
<Button
android:id="@+id/loadimage1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Load Image 1" />
<TextView
android:id="@+id/sourceuri1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/startactivity"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Start Another Activity" />
<ImageView
android:id="@+id/result"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Activity2.java, code of the second activity.
package com.example.androidcommonbitmap;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
public class Activity2 extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity2_layout);
ImageView image2 = (ImageView)findViewById(R.id.image2);
image2.setImageBitmap(CommonBitmap.bitmap);
Button btnFinish = (Button)findViewById(R.id.finish);
btnFinish.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0) {
setResult(RESULT_OK);
finish();
}});
}
}
activity2_layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".MainActivity" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold"
android:layout_gravity="center_horizontal"
android:autoLink="web" />
<Button
android:id="@+id/finish"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Finish" />
<ImageView
android:id="@+id/image2"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Finally, add the second activity Activity2.java to AndroidManifest.xml.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.androidcommonbitmap"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.androidcommonbitmap.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.example.androidcommonbitmap.Activity2"
android:label="@string/app_name" >
</activity>
</application>
</manifest>
Download the files.
more: Something about processing images in Android
OpenGL ES 2 for Android: A Quick-Start Guide
OpenGL ES 2 for Android: A Quick-Start Guide
Android is booming like never before, with millions of devices shipping every day. It's never been a better time to learn how to create your own 3D games and live wallpaper for Android. You'll find out all about shaders and the OpenGL pipeline, and discover the power of OpenGL ES 2.0, which is much more feature-rich than its predecessor. If you can program in Java and you have a creative vision that you'd like to share with the world, then this is the book for you.
This book will teach you everything you need to know to create compelling graphics on Android. You'll learn the basics of OpenGL by building a simple game of air hockey, and along the way, you'll see how to initialize OpenGL and program the graphics pipeline using shaders. Each lesson builds upon the one before it, as you add colors, shading, 3D projections, touch interaction, and more.
Then, you'll find out how to turn your idea into a live wallpaper that can run on the home screen. You'll learn about more advanced effects involving particles, lighting models, and the depth buffer. You'll understand what to look for when debugging your program, and what to watch out for when deploying to the market.
OpenGL can be somewhat of a dark art to the uninitiated. As you read this book, you'll learn each new concept from first principles. You won't just learn about a feature; you'll also understand how it works, and why it works the way it does. Everything you learn is forward-compatible with the just-released OpenGL ES 3, and you can even apply these techniques to other platforms, such as iOS or HTML5 WebGL.
Android is booming like never before, with millions of devices shipping every day. It's never been a better time to learn how to create your own 3D games and live wallpaper for Android. You'll find out all about shaders and the OpenGL pipeline, and discover the power of OpenGL ES 2.0, which is much more feature-rich than its predecessor. If you can program in Java and you have a creative vision that you'd like to share with the world, then this is the book for you.
This book will teach you everything you need to know to create compelling graphics on Android. You'll learn the basics of OpenGL by building a simple game of air hockey, and along the way, you'll see how to initialize OpenGL and program the graphics pipeline using shaders. Each lesson builds upon the one before it, as you add colors, shading, 3D projections, touch interaction, and more.
Then, you'll find out how to turn your idea into a live wallpaper that can run on the home screen. You'll learn about more advanced effects involving particles, lighting models, and the depth buffer. You'll understand what to look for when debugging your program, and what to watch out for when deploying to the market.
OpenGL can be somewhat of a dark art to the uninitiated. As you read this book, you'll learn each new concept from first principles. You won't just learn about a feature; you'll also understand how it works, and why it works the way it does. Everything you learn is forward-compatible with the just-released OpenGL ES 3, and you can even apply these techniques to other platforms, such as iOS or HTML5 WebGL.
Thursday, August 22, 2013
Processing on desktop vs Processing for Android
It's the same code run Processing on desktop and Android, with Android Mode.
Run on Nexus One:
Run on desktop:
The example code:
Related:
- Setup Processing for Android development
- Hello World of Processing for Android
Cross post: Arduino-er blog - Processing on desktop vs Processing for Android
Run on Nexus One:
Run on desktop:
The example code:
void setup(){
size(400, 300);
background(0);
stroke(255);
}
void draw() {
noFill();
if(mousePressed){
background(0);
point(mouseX, mouseY);
line(80, 50, mouseX, mouseY);
line(50, 200, 350, 250);
curve(80, 50, mouseX, mouseY, 50, 200, 350, 250);
}
}
Related:
- Setup Processing for Android development
- Hello World of Processing for Android
Cross post: Arduino-er blog - Processing on desktop vs Processing for Android
Example to create shadow frame for image
package com.example.androidframeimage;
import java.io.FileNotFoundException;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuffXfermode;
import android.graphics.Bitmap.Config;
import android.graphics.PorterDuff.Mode;
import android.graphics.Rect;
import android.graphics.RectF;
public class MainActivity extends Activity {
Button btnLoadImage1;
TextView textSource1;
Button btnProcessing;
ImageView imageResult;
final int RQS_IMAGE1 = 1;
Uri source1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnLoadImage1 = (Button)findViewById(R.id.loadimage1);
textSource1 = (TextView)findViewById(R.id.sourceuri1);
btnProcessing = (Button)findViewById(R.id.processing);
imageResult = (ImageView)findViewById(R.id.result);
btnLoadImage1.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0) {
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, RQS_IMAGE1);
}});
btnProcessing.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
if(source1 != null){
Bitmap processedBitmap = ProcessingBitmap();
if(processedBitmap != null){
imageResult.setImageBitmap(processedBitmap);
Toast.makeText(getApplicationContext(),
"Done",
Toast.LENGTH_LONG).show();
}else{
Toast.makeText(getApplicationContext(),
"Something wrong in processing!",
Toast.LENGTH_LONG).show();
}
}else{
Toast.makeText(getApplicationContext(),
"Select image!",
Toast.LENGTH_LONG).show();
}
}});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK){
switch (requestCode){
case RQS_IMAGE1:
source1 = data.getData();
textSource1.setText(source1.toString());
break;
}
}
}
private Bitmap ProcessingBitmap(){
Bitmap bm1 = null;
Bitmap newBitmap = null;
Bitmap newShadowBitmap = null;
try {
bm1 = BitmapFactory.decodeStream(
getContentResolver().openInputStream(source1));
int w = bm1.getWidth();
int h = bm1.getHeight();
Config config = bm1.getConfig();
if(config == null){
config = Bitmap.Config.ARGB_8888;
}
newBitmap = Bitmap.createBitmap(w, h, config);
Canvas newCanvas = new Canvas(newBitmap);
newCanvas.drawColor(Color.BLACK);
Paint paint = new Paint();
paint.setColor(Color.WHITE);
Rect frame = new Rect(
(int)(w*0.05),
(int)(w*0.05),
(int)(w*0.95),
(int)(h*0.95));
RectF frameF = new RectF(frame);
newCanvas.drawRect(frameF, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.DARKEN));
newCanvas.drawBitmap(bm1, 0, 0, paint);
/*
* Create shadow like outer frame
*/
//create BLACK bitmap with same size of the image
Bitmap bitmapFullGray = Bitmap.createBitmap(w, h, config);
Canvas canvasFullGray = new Canvas(bitmapFullGray);
canvasFullGray.drawColor(0xFF808080);
//create bigger bitmap with shadow frame
int shadowThick = 100;
int shadowRadius = 50;
newShadowBitmap = Bitmap.createBitmap(w+shadowThick+shadowRadius,
h+shadowThick+shadowRadius, config);
Canvas newShadowCanvas = new Canvas(newShadowBitmap);
newShadowCanvas.drawColor(Color.WHITE);
//generate shadow
Paint paintShadow = new Paint();
paintShadow.setShadowLayer(shadowRadius, shadowThick, shadowThick, 0xFF000000);
newShadowCanvas.drawBitmap(bitmapFullGray, 0, 0, paintShadow);
//Place the image
paintShadow.clearShadowLayer();
newShadowCanvas.drawBitmap(newBitmap, 0, 0, paintShadow);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return newShadowBitmap;
}
}
Layout refer to last exercise "Create frame on Bitmap image".
Download the files.
more: Something about processing images in Android
Wednesday, August 21, 2013
Create frame on Bitmap image
With PorterDuffXfermode, we can apply frame on bitmap image. By creating bitmap with frame pattern, then merging image using Paint with Xfermode. You can check effects of various PorterDuffXfermode in last exercise.
Download the files.
next: Create shadow frame for image
more: Something about processing images in Android
package com.example.androidframeimage;
import java.io.FileNotFoundException;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuffXfermode;
import android.graphics.Bitmap.Config;
import android.graphics.PorterDuff.Mode;
import android.graphics.Rect;
import android.graphics.RectF;
public class MainActivity extends Activity {
Button btnLoadImage1;
TextView textSource1;
Button btnProcessing;
ImageView imageResult;
final int RQS_IMAGE1 = 1;
Uri source1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnLoadImage1 = (Button)findViewById(R.id.loadimage1);
textSource1 = (TextView)findViewById(R.id.sourceuri1);
btnProcessing = (Button)findViewById(R.id.processing);
imageResult = (ImageView)findViewById(R.id.result);
btnLoadImage1.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0) {
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, RQS_IMAGE1);
}});
btnProcessing.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
if(source1 != null){
Bitmap processedBitmap = ProcessingBitmap();
if(processedBitmap != null){
imageResult.setImageBitmap(processedBitmap);
Toast.makeText(getApplicationContext(),
"Done",
Toast.LENGTH_LONG).show();
}else{
Toast.makeText(getApplicationContext(),
"Something wrong in processing!",
Toast.LENGTH_LONG).show();
}
}else{
Toast.makeText(getApplicationContext(),
"Select image!",
Toast.LENGTH_LONG).show();
}
}});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK){
switch (requestCode){
case RQS_IMAGE1:
source1 = data.getData();
textSource1.setText(source1.toString());
break;
}
}
}
private Bitmap ProcessingBitmap(){
Bitmap bm1 = null;
Bitmap newBitmap = null;
try {
bm1 = BitmapFactory.decodeStream(
getContentResolver().openInputStream(source1));
int w = bm1.getWidth();
int h = bm1.getHeight();
Config config = bm1.getConfig();
if(config == null){
config = Bitmap.Config.ARGB_8888;
}
newBitmap = Bitmap.createBitmap(w, h, config);
Canvas newCanvas = new Canvas(newBitmap);
newCanvas.drawColor(Color.WHITE);
Paint paint = new Paint();
paint.setColor(Color.BLACK);
Rect frame = new Rect(
(int)(w*0.05),
(int)(w*0.05),
(int)(w*0.95),
(int)(h*0.95));
RectF frameF = new RectF(frame);
newCanvas.drawRoundRect(frameF, (float)(w*0.05), (float)(h*0.05), paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SCREEN));
newCanvas.drawBitmap(bm1, 0, 0, paint);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return newBitmap;
}
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".MainActivity" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold"
android:layout_gravity="center_horizontal"
android:autoLink="web" />
<Button
android:id="@+id/loadimage1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Load Image 1" />
<TextView
android:id="@+id/sourceuri1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/processing"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Create Image Frame" />
<ImageView
android:id="@+id/result"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Download the files.
next: Create shadow frame for image
more: Something about processing images in Android
Tuesday, August 20, 2013
Merge images with PorterDuffXfermode
This exercise demonstrate how to merge two images with Paint of PorterDuffXfermode. You can select various PorterDuff.Mode to merge the images to see the effect.
Download the files.
You can download and try the APK here. (The exercises have not take care the bitmap size, and any resizing. So don't test with big picture, otherwise OutOfMemoryError or "Bitmap too large to be uploaded into a texture" will happen).
more: Something about processing images in Android
package com.test.androidimageprocessing;
import java.io.FileNotFoundException;
import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import com.example.androidimageprocessing.R;
public class MainActivity extends Activity {
Button btnLoadImage1, btnLoadImage2;
TextView textSource1, textSource2;
Button btnProcessing;
ImageView imageResult;
Spinner spinnerMode;
final int RQS_IMAGE1 = 1;
final int RQS_IMAGE2 = 2;
Uri source1, source2;
String[] arrayModeName = {
"ADD",
"CLEAR",
"DARKEN",
"DST",
"DST_ATOP",
"DST_IN",
"DST_OUT",
"DST_OVER",
"LIGHTEN",
"MULTIPLY",
"OVERLAY",
"SCREEN",
"SRC",
"SRC_ATOP",
"SRC_IN",
"SRC_OUT",
"SRC_OVER",
"XOR" };
/*
* To use Mode.ADD and Mode.OVERLAY, android:minSdkVersion
* have to be set "11" or higher.
*/
PorterDuff.Mode[] arrayMode = {
Mode.ADD,
Mode.CLEAR,
Mode.DARKEN,
Mode.DST,
Mode.DST_ATOP,
Mode.DST_IN,
Mode.DST_OUT,
Mode.DST_OVER,
Mode.LIGHTEN,
Mode.MULTIPLY,
Mode.OVERLAY,
Mode.SCREEN,
Mode.SRC,
Mode.SRC_ATOP,
Mode.SRC_IN,
Mode.SRC_OUT,
Mode.SRC_OVER,
Mode.XOR };
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnLoadImage1 = (Button)findViewById(R.id.loadimage1);
btnLoadImage2 = (Button)findViewById(R.id.loadimage2);
textSource1 = (TextView)findViewById(R.id.sourceuri1);
textSource2 = (TextView)findViewById(R.id.sourceuri2);
btnProcessing = (Button)findViewById(R.id.processing);
imageResult = (ImageView)findViewById(R.id.result);
spinnerMode = (Spinner)findViewById(R.id.mode);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity.this,
android.R.layout.simple_spinner_item, arrayModeName);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinnerMode.setAdapter(adapter);
btnLoadImage1.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0) {
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, RQS_IMAGE1);
}});
btnLoadImage2.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0) {
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, RQS_IMAGE2);
}});
btnProcessing.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
if(source1 != null && source2 != null){
Bitmap processedBitmap = ProcessingBitmap();
if(processedBitmap != null){
imageResult.setImageBitmap(processedBitmap);
Toast.makeText(getApplicationContext(),
"Done",
Toast.LENGTH_LONG).show();
}else{
Toast.makeText(getApplicationContext(),
"Something wrong in processing!",
Toast.LENGTH_LONG).show();
}
}else{
Toast.makeText(getApplicationContext(),
"Select both image!",
Toast.LENGTH_LONG).show();
}
}});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK){
switch (requestCode){
case RQS_IMAGE1:
source1 = data.getData();
textSource1.setText(source1.toString());
break;
case RQS_IMAGE2:
source2 = data.getData();
textSource2.setText(source2.toString());
break;
}
}
}
private Bitmap ProcessingBitmap(){
Bitmap bm1 = null;
Bitmap bm2 = null;
Bitmap newBitmap = null;
try {
bm1 = BitmapFactory.decodeStream(
getContentResolver().openInputStream(source1));
bm2 = BitmapFactory.decodeStream(
getContentResolver().openInputStream(source2));
int w;
if(bm1.getWidth() >= bm2.getWidth()){
w = bm1.getWidth();
}else{
w = bm2.getWidth();
}
int h;
if(bm1.getHeight() >= bm2.getHeight()){
h = bm1.getHeight();
}else{
h = bm2.getHeight();
}
Config config = bm1.getConfig();
if(config == null){
config = Bitmap.Config.ARGB_8888;
}
newBitmap = Bitmap.createBitmap(w, h, config);
Canvas newCanvas = new Canvas(newBitmap);
newCanvas.drawBitmap(bm1, 0, 0, null);
Paint paint = new Paint();
int selectedPos = spinnerMode.getSelectedItemPosition();
PorterDuff.Mode selectedMode = arrayMode[selectedPos];
paint.setXfermode(new PorterDuffXfermode(selectedMode));
newCanvas.drawBitmap(bm2, 0, 0, paint);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return newBitmap;
}
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".MainActivity" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold"
android:layout_gravity="center_horizontal"
android:autoLink="web" />
<Button
android:id="@+id/loadimage1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Load Image 1" />
<TextView
android:id="@+id/sourceuri1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/loadimage2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Load Image 2" />
<TextView
android:id="@+id/sourceuri2"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Spinner
android:id="@+id/mode"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/processing"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Processing" />
<ImageView
android:id="@+id/result"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Download the files.
You can download and try the APK here. (The exercises have not take care the bitmap size, and any resizing. So don't test with big picture, otherwise OutOfMemoryError or "Bitmap too large to be uploaded into a texture" will happen).
more: Something about processing images in Android
Monday, August 19, 2013
Place TextView over ImageView
Last exercise how to "Draw text on bitmap". If you only want to display text over image, not draw text on bitmap, you can simple place TextView over ImageView.
Layout
MainActivity Java code:
Download the files.
Layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold" />
<Button
android:id="@+id/loadimage1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Load Image 1" />
<TextView
android:id="@+id/sourceuri1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<EditText
android:id="@+id/caption"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/processing"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Draw text on Bitmap" />
<RelativeLayout
android:id="@+id/imagelayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="@+id/result"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"/>
<TextView
android:id="@+id/resulttext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="30sp"
android:textStyle="bold"
android:layout_alignLeft="@id/result"
android:layout_alignTop="@id/result"
android:layout_alignRight="@id/result"
android:layout_alignBottom="@id/result"/>
</RelativeLayout>
</LinearLayout>
MainActivity Java code:
package com.example.androiddrawtextonbitmap;
import java.io.FileNotFoundException;
import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
Button btnLoadImage1;
TextView textSource1;
EditText editTextCaption;
Button btnProcessing;
ImageView imageResult;
TextView textResult;
final int RQS_IMAGE1 = 1;
Uri source1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnLoadImage1 = (Button)findViewById(R.id.loadimage1);
textSource1 = (TextView)findViewById(R.id.sourceuri1);
editTextCaption = (EditText)findViewById(R.id.caption);
btnProcessing = (Button)findViewById(R.id.processing);
imageResult = (ImageView)findViewById(R.id.result);
textResult = (TextView)findViewById(R.id.resulttext);
btnLoadImage1.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0) {
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, RQS_IMAGE1);
}});
btnProcessing.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
if(source1 != null){
Bitmap processedBitmap = ProcessingBitmap();
if(processedBitmap != null){
imageResult.setImageBitmap(processedBitmap);
Toast.makeText(getApplicationContext(),
"Done",
Toast.LENGTH_LONG).show();
}else{
Toast.makeText(getApplicationContext(),
"Something wrong in processing!",
Toast.LENGTH_LONG).show();
}
}else{
Toast.makeText(getApplicationContext(),
"Select both image!",
Toast.LENGTH_LONG).show();
}
}});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK){
switch (requestCode){
case RQS_IMAGE1:
source1 = data.getData();
textSource1.setText(source1.toString());
break;
}
}
}
private Bitmap ProcessingBitmap(){
Bitmap newBitmap = null;
try {
newBitmap = BitmapFactory.decodeStream(
getContentResolver().openInputStream(source1));
String captionString = editTextCaption.getText().toString();
if(captionString != null){
textResult.setText(captionString);
}else{
Toast.makeText(getApplicationContext(),
"caption empty!",
Toast.LENGTH_LONG).show();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return newBitmap;
}
}
Download the files.
Friday, August 16, 2013
Display Spinner inside PopupWindow
It's a example to display Spinner in PopupWindow. For simple example of using Android PopupWindow, refer to the post.
Create /res/layout/popup.xml to define the view of the PopupWindow. Add <Spinner> with android:spinnerMode="dialog".
Main activity Java code to handle the PopupWindow and Spinner.
Layout file.
Download the files.
Create /res/layout/popup.xml to define the view of the PopupWindow. Add <Spinner> with android:spinnerMode="dialog".
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@android:color/background_light"
android:orientation="vertical" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="1dp"
android:background="@android:color/darker_gray"
android:orientation="vertical" >
>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="It's a PopupWindow" />
<ImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher" />
<Spinner
android:id="@+id/popupspinner"
android:spinnerMode="dialog"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/dismiss"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Dismiss" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
Main activity Java code to handle the PopupWindow and Spinner.
package com.example.androidpopupwindow;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.PopupWindow;
import android.widget.Spinner;
import android.app.Activity;
public class MainActivity extends Activity {
String[] DayOfWeek = {"Sunday", "Monday", "Tuesday",
"Wednesday", "Thursday", "Friday", "Saturday"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Button btnOpenPopup = (Button) findViewById(R.id.openpopup);
btnOpenPopup.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View arg0) {
LayoutInflater layoutInflater =
(LayoutInflater)getBaseContext()
.getSystemService(LAYOUT_INFLATER_SERVICE);
View popupView = layoutInflater.inflate(R.layout.popup, null);
final PopupWindow popupWindow = new PopupWindow(
popupView, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
Button btnDismiss = (Button)popupView.findViewById(R.id.dismiss);
Spinner popupSpinner = (Spinner)popupView.findViewById(R.id.popupspinner);
ArrayAdapter<String> adapter =
new ArrayAdapter<String>(MainActivity.this,
android.R.layout.simple_spinner_item, DayOfWeek);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
popupSpinner.setAdapter(adapter);
btnDismiss.setOnClickListener(new Button.OnClickListener(){
@Override
public void onClick(View v) {
popupWindow.dismiss();
}});
popupWindow.showAsDropDown(btnOpenPopup, 50, -30);
}
});
}
}
Layout file.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold"
android:layout_gravity="center_horizontal"
android:autoLink="web" />
<Button
android:id="@+id/openpopup"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Open Popup Window" />
</LinearLayout>
Download the files.
Example to draw Bitmap with ShadowLayer
In the below screen capture, the background bitmap is draw normally, the upper left bitmap of Rubber Duck is draw using Paint with ShadowLayer, the middle one is the shadow layer of the Rubber Duck bitmap.
The layout file refer to the post "Combine bitmap side-by-side".
Download the files.
more: Something about processing images in Android
package com.test.androidimageprocessing;
import java.io.FileNotFoundException;
import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.example.androidimageprocessing.R;
public class MainActivity extends Activity {
Button btnLoadImage1, btnLoadImage2;
TextView textSource1, textSource2;
Button btnProcessing;
ImageView imageResult;
final int RQS_IMAGE1 = 1;
final int RQS_IMAGE2 = 2;
Uri source1, source2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnLoadImage1 = (Button)findViewById(R.id.loadimage1);
btnLoadImage2 = (Button)findViewById(R.id.loadimage2);
textSource1 = (TextView)findViewById(R.id.sourceuri1);
textSource2 = (TextView)findViewById(R.id.sourceuri2);
btnProcessing = (Button)findViewById(R.id.processing);
imageResult = (ImageView)findViewById(R.id.result);
btnLoadImage1.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0) {
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, RQS_IMAGE1);
}});
btnLoadImage2.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0) {
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, RQS_IMAGE2);
}});
btnProcessing.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
if(source1 != null && source2 != null){
Bitmap processedBitmap = ProcessingBitmap();
if(processedBitmap != null){
imageResult.setImageBitmap(processedBitmap);
Toast.makeText(getApplicationContext(),
"Done",
Toast.LENGTH_LONG).show();
}else{
Toast.makeText(getApplicationContext(),
"Something wrong in processing!",
Toast.LENGTH_LONG).show();
}
}else{
Toast.makeText(getApplicationContext(),
"Select both image!",
Toast.LENGTH_LONG).show();
}
}});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK){
switch (requestCode){
case RQS_IMAGE1:
source1 = data.getData();
textSource1.setText(source1.toString());
break;
case RQS_IMAGE2:
source2 = data.getData();
textSource2.setText(source2.toString());
break;
}
}
}
private Bitmap ProcessingBitmap(){
Bitmap bm1 = null;
Bitmap bm2 = null;
Bitmap newBitmap = null;
try {
bm1 = BitmapFactory.decodeStream(
getContentResolver().openInputStream(source1));
bm2 = BitmapFactory.decodeStream(
getContentResolver().openInputStream(source2));
int w;
if(bm1.getWidth() >= bm2.getWidth()){
w = bm1.getWidth();
}else{
w = bm2.getWidth();
}
int h;
if(bm1.getHeight() >= bm2.getHeight()){
h = bm1.getHeight();
}else{
h = bm2.getHeight();
}
Config config = bm1.getConfig();
if(config == null){
config = Bitmap.Config.ARGB_8888;
}
newBitmap = Bitmap.createBitmap(w, h, config);
Canvas newCanvas = new Canvas(newBitmap);
newCanvas.drawBitmap(bm1, 0, 0, null);
Paint paint = new Paint();
paint.setShadowLayer(50.0f, 200.0f, 100.0f, 0xFF000000);
newCanvas.drawBitmap(bm2, 0, 0, paint);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return newBitmap;
}
}
The layout file refer to the post "Combine bitmap side-by-side".
Download the files.
more: Something about processing images in Android