Always On, Always Connected Week 4 - Mobile Media

Mobile Media

What is the world's best camera?

Most Popular Cameras in the Flickr Community

Mobile phones have cameras built in that rival the best point and shoot cameras out there. Some even have optical zoom, built-in flashes and so on.

Not only capture but … (capture, storage, editing, viewing, sharing)

Impossible before, possible now:

Polaroid Android

Say, Can You Make Phone Calls on That Camera?

HDR 35 Fantastic HDR Pictures

Instagram

Vine and Vinepeek

Snapchat

What about?

Cameras, the new lighter

The rise of the camera-phone
Everywhere you go these days, there are people with camera-phones – many of us record, document, and upload the minutae of our lives. But, ultimately, should we be doing it just because we can?

Why are we compelled to document everything? Are we missing anything in the process?

What about privacy? Activism/Protest? Surveillance?
Illicit photos?

Vancouver Riot Identify Suspects
Arab Spring
Remove Location Information on Photos

Utilizing the built-in Camera via an Intent

Intent i = new Intent (android.provider.MediaStore.ACTION_IMAGE_CAPTURE); 
startActivityForResult(i, CAMERA_RESULT);
protected void onActivityResult(int requestCode, int resultCode, Intent intent) { 	
	...
	Get Bundle extras = intent.getExtras(); 
	Bitmap bmp = (Bitmap) extras.get("data");
	....

Capturing Full Size Images

File imageFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/myfavoritepicture.jpg"); 
Uri imageFileUri = Uri.fromFile(imageFile);
Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
i.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, imageFileUri);
startActivityForResult(i, CAMERA_RESULT);

Displaying Large Images

BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options(); 
bmpFactoryOptions.inSampleSize = 8; 
Bitmap bmp = BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions);
		

Sizing based on screen

BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options(); 
bmpFactoryOptions.inJustDecodeBounds = true; 
Bitmap bmp = BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions);
int heightRatio = (int)Math.ceil(bmpFactoryOptions.outHeight/(float) currentDisplay.getHeight()); 
int widthRatio = (int)Math.ceil(bmpFactoryOptions.outWidth/(float) currentDisplay.getWidth());
if (heightRatio > 1 && widthRatio > 1) {
	if (heightRatio > widthRatio) {
		bmpFactoryOptions.inSampleSize = heightRatio; 
	} else {
		bmpFactoryOptions.inSampleSize = widthRatio;
	}
}
bmpFactoryOptions.inJustDecodeBounds = false; 
bmp = BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions);
		

Building a Custom Camera Application

Tricky to get right but offers a more flexible UI

Permissions

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

Camera Preview Surface

<SurfaceView android:id="@+id/CameraView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"></SurfaceView>

SurfaceHolder.Callback

public class SnapShot extends Activity implements SurfaceHolder.Callback {
	SurfaceView cameraView; 
	SurfaceHolder surfaceHolder;

	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState); 
		setContentView(R.layout.main);
		cameraView = (SurfaceView) this.findViewById(R.id.CameraView); 
		surfaceHolder = cameraView.getHolder(); 
		surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 
		surfaceHolder.addCallback(this);
	}
	
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {} 
public void surfaceCreated(SurfaceHolder holder) {} 
public void surfaceDestroyed(SurfaceHolder holder) {}
		

Implementing the Camera

Camera camera; 

public void surfaceCreated(SurfaceHolder holder) {
	camera = Camera.open();
	try {
		camera.setPreviewDisplay(holder);
	} catch (IOException exception) {
		camera.release();
	}
	camera.setDisplayOrientation(90);
	camera.startPreview();
}

public void surfaceDestroyed(SurfaceHolder holder) {
camera.stopPreview(); camera.release();
}
		

Capturing and Saving

public class SnapShot extends Activity implements SurfaceHolder.Callback, Camera.PictureCallback {
...
	public void onPictureTaken(byte[] data, Camera camera) { 
		Uri imageFileUri = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, new ContentValues()); 
		try {
			OutputStream imageFileOS = getContentResolver().openOutputStream(imageFileUri); 
			imageFileOS.write(data); 
			imageFileOS.flush(); 
			imageFileOS.close();
		} catch (FileNotFoundException e) {
		} catch (IOException e) {}
	}

	public void onCreate(Bundle savedInstanceState) { 
	...
		cameraView.setFocusable(true); 
		cameraView.setFocusableInTouchMode(true); 
		cameraView.setClickable(true); 
		cameraView.setOnClickListener(this);
	}
	
	public void onClick(View v) { 
		camera.takePicture(null, null, null, this);
	}
		

Creating a Double Exposure Camera App

Update onPictureTaken

    File imageFile1;
    File imageFile2;
    int currentPicture = 1;
    
    public void onPictureTaken(byte[] data, Camera camera) { 
		try {
			File imageFile = File.createTempFile("doubleexposure", ".jpg");
			FileOutputStream imageFileOS = new FileOutputStream(imageFile);
			imageFileOS.write(data); 
			imageFileOS.flush(); 
			imageFileOS.close();

			if (currentPicture == 1) {
				imageFile1 = imageFile;
				currentPicture++;
				camera.startPreview();
			} else if (currentPicture == 2) {
				imageFile2 = imageFile;
				cameraView.setVisibility(View.INVISIBLE);

			...
		

Add an ImageView

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent">
	<SurfaceView android:id="@+id/CameraView" 
		android:layout_width="fill_parent" 
		android:layout_height="fill_parent">
	</SurfaceView>
	<ImageView android:id="@+id/DoubleExposureView"
		android:layout_width="fill_parent"
		android:layout_height="fill_parent">
	</ImageView>
</FrameLayout>
		

Create the Bitmaps

BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options(); 
bmpFactoryOptions.inJustDecodeBounds = true; 
Bitmap bmp = BitmapFactory.decodeFile(imageFile1.getPath(), bmpFactoryOptions);
int heightRatio = (int)Math.ceil(bmpFactoryOptions.outHeight/(float)getWindowManager().getDefaultDisplay().getHeight()); 
int widthRatio = (int)Math.ceil(bmpFactoryOptions.outWidth/(float)getWindowManager().getDefaultDisplay().getWidth());
if (heightRatio > 1 && widthRatio > 1) {
	if (heightRatio > widthRatio) {
		bmpFactoryOptions.inSampleSize = heightRatio; 
	} else {
		bmpFactoryOptions.inSampleSize = widthRatio;
	}
}
bmpFactoryOptions.inJustDecodeBounds = false; 
Bitmap picture1bmp = BitmapFactory.decodeFile(imageFile1.getPath(), bmpFactoryOptions);    
Bitmap picture2bmp = BitmapFactory.decodeFile(imageFile2.getPath(), bmpFactoryOptions);		
		

Create the Bitmap for Drawing

Bitmap drawingBmp = Bitmap.createBitmap(picture1bmp.getWidth(), picture1bmp.getHeight(), picture1bmp.getConfig());
Canvas canvas = new Canvas(drawingBmp);
Paint paint = new Paint();
		

Draw the first Bitmap

canvas.drawBitmap(picture1bmp, 0, 0, paint);
		

Set the Paint and Draw the second Bitmap

paint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.MULTIPLY));
canvas.drawBitmap(picture2bmp, 0, 0, paint);
		

Set and Display the ImageView

ImageView doubleExposureView = (ImageView) this.findViewById(R.id.DoubleExposureView);
doubleExposureView.setImageBitmap(drawingBmp);