package org.sana.android; import java.io.IOException; import java.io.InputStream; import android.app.Dialog; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.net.Uri; import android.view.GestureDetector; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.GestureDetector.OnGestureListener; import android.view.View.OnClickListener; import android.view.View.OnTouchListener; import android.view.ViewGroup.LayoutParams; import android.widget.Button; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ImageView.ScaleType; import org.sana.R; /** * ImagePreviewDialog for reviewing captured images. * * Quick user hints: Zoom in, Zoom out, center image, and close dialog (back) * buttons available. * * Also, a user can flick the image or pan it by dragging the image. If the user * holds down a finger to the image, it will reset (center and resize). If a * user taps on the image, it will zoom in. * * @author Sana Dev Team */ public class ImagePreviewDialog extends Dialog implements OnClickListener, OnTouchListener, OnGestureListener { private static int BITMAP_SAMPLE_SIZE = 1; private Button zoomInButton, zoomOutButton, centerButton, endButton, rotateButton, fitButton; private ImageView imageView; private GestureDetector gestureDetector; private float scaledWidth, scaledHeight, transX, transY; private float imageWidth, imageHeight; private float originalWidth, originalHeight; private final float zoomConst = 0.4f; private final float initScaledWidth = 0.55f, initScaledHeight = 0.55f; /** * Default Constructor * @param c */ public ImagePreviewDialog(Context c) { super(c); LinearLayout fv = new LinearLayout(c); imageView = new ImageView(c); zoomInButton = new Button(c); zoomInButton.setText(c.getText(R.string.general_zoom_in)); zoomInButton.setOnClickListener(this); zoomOutButton = new Button(c); zoomOutButton.setText(c.getText(R.string.general_zoom_out)); zoomOutButton.setOnClickListener(this); centerButton = new Button(c); centerButton.setText(c.getText(R.string.general_center)); centerButton.setOnClickListener(this); endButton = new Button(c); endButton.setText(c.getText(R.string.general_back)); endButton.setOnClickListener(this); LinearLayout buttonContainer = new LinearLayout(c); buttonContainer.setOrientation(LinearLayout.HORIZONTAL); buttonContainer.addView(zoomInButton); buttonContainer.addView(zoomOutButton); buttonContainer.addView(centerButton); buttonContainer.addView(endButton); imageView.setOnClickListener(this); imageView.setOnTouchListener(this); gestureDetector = new GestureDetector(this); // height is a hack set for the G1 phone // imageView.setLayoutParams(new LayoutParams(-1, -1)); fv.addView(buttonContainer); fv.addView(imageView); fv.setOrientation(LinearLayout.VERTICAL); fv.setGravity(Gravity.CENTER_HORIZONTAL); fv.setLayoutParams(new LayoutParams(150, -1)); setTitle("View Photos"); setContentView(fv); } /** {@inheritDoc} */ @Override public void onClick(View v) { if (v == zoomInButton) { zoomIn(); } else if (v == zoomOutButton) { zoomOut(); } else if (v == centerButton) { center(); } else if (v == endButton) { this.dismiss(); } } /** * Loads a bitmap image into the image preview dialog window. * @param is inputstream of the bitmap image */ public void showImage(Uri imageUri) throws IOException { BitmapFactory.Options bmo = new BitmapFactory.Options(); // Get the image size. bmo.inJustDecodeBounds = true; InputStream imageInputStream = getContext().getContentResolver().openInputStream(imageUri); BitmapFactory.decodeStream(imageInputStream, null, bmo); int width = bmo.outWidth; int height = bmo.outHeight; bmo.inJustDecodeBounds = false; imageInputStream.close(); // Load the bitmap and downsample it to 1000 pixels along its largest // dimension. int maxDimension = (width > height) ? width : height; bmo.inSampleSize = maxDimension / 1000; imageInputStream = getContext().getContentResolver().openInputStream( imageUri); Bitmap loadedBitmap = BitmapFactory.decodeStream(imageInputStream, null, bmo); originalWidth = (float) (loadedBitmap.getWidth()); originalHeight = (float) (loadedBitmap.getHeight()); scaledWidth = initScaledWidth; scaledHeight = initScaledHeight; imageView.setImageBitmap(loadedBitmap); transX = 0f; transY = 0f; updateSize(); setImageMatrix(); } // for scaling void updateSize() { imageWidth = originalWidth * scaledWidth; imageHeight = originalHeight * scaledHeight; } // for scaling void setImageMatrix() { Matrix mtrx = new Matrix(); mtrx.postScale(scaledWidth, scaledHeight); mtrx.postTranslate(transX, transY); imageView.setImageMatrix(mtrx); imageView.setScaleType(ScaleType.MATRIX); imageView.invalidate(); } /** * Pan an image. * @param dx left/right movement amount * @param dy up/down movement amount */ void translate(float dx, float dy) { transX -= dx; transY -= dy; setImageMatrix(); } /** * Zooms in the image in by a constant factor (zoomConst). */ void zoomIn() { float origImageWidth = imageWidth; float origImageHeight = imageHeight; scaledWidth += zoomConst; scaledHeight += zoomConst; updateSize(); float widthIncrease = imageWidth - origImageWidth; float heightIncrease = imageHeight - origImageHeight; translate(0.5f * widthIncrease, 0.5f * heightIncrease); //setImageMatrix(); } /** * Zooms out the image in by a constant factor (zoomConst). */ void zoomOut() { float origImageWidth = imageWidth; float origImageHeight = imageHeight; if (scaledWidth > zoomConst) scaledWidth -= zoomConst; if (scaledHeight > zoomConst) scaledHeight -= zoomConst; updateSize(); float widthIncrease = imageWidth - origImageWidth; float heightIncrease = imageHeight - origImageHeight; translate(0.5f * widthIncrease, 0.5f * heightIncrease); //setImageMatrix(); } /** * Centers the image in the image preview dialog. */ void center() { transX = (imageView.getWidth() / 2.0f) - (imageWidth / 2.0f); transY = (imageView.getHeight() / 2.0f) - (imageHeight / 2.0f); updateSize(); translate(0, 0); } /** {@inheritDoc} */ @Override public boolean onTouch(View v, MotionEvent me) { if (v == imageView) { gestureDetector.onTouchEvent(me); } return false; } /** {@inheritDoc} */ @Override public boolean onDown(MotionEvent arg0) { return false; } /** {@inheritDoc} */ @Override public boolean onFling(MotionEvent arg0, MotionEvent arg1, float velocityX, float velocityY) { //Log.i("imagepreview", "fling x:" + velocityX + " y:" + velocityY); translate((float) (-velocityX / 8.0), (float) (-velocityY / 8.0)); return false; } /** * Reset image position and size when a finger is held to the screen. */ public void onLongPress(MotionEvent arg0) { // Log.d("imagepreview", "long press"); scaledWidth = initScaledWidth; scaledHeight = initScaledHeight; updateSize(); center(); } /** {@inheritDoc} */ @Override public boolean onScroll(MotionEvent arg0, MotionEvent arg1, float distanceX, float distanceY) { //Log.i("imagepreview", "scroll x:" + distanceX + " y:" + distanceY); translate((float) (distanceX / 1.0), (float) (distanceY / 1.0)); return false; } /** {@inheritDoc} */ @Override public void onShowPress(MotionEvent arg0) { // Log.d("imagepreview", "show press"); } /** * Zoom in when screen is tapped. */ public boolean onSingleTapUp(MotionEvent arg0) { //Log.d("imagepreview", "single tap"); zoomIn(); return false; } }