org.witness.informacam.app.editors.image.ImageRegion.java Source code

Java tutorial

Introduction

Here is the source code for org.witness.informacam.app.editors.image.ImageRegion.java

Source

package org.witness.informacam.app.editors.image;

import java.util.Enumeration;
import java.util.Properties;

import net.londatiga.android.ActionItem;
import net.londatiga.android.QuickAction;
import net.londatiga.android.QuickAction.OnActionItemClickListener;

import org.json.JSONException;
import org.json.JSONObject;
import org.witness.informacam.R;
import org.witness.informacam.app.editors.image.filters.CrowdPixelizeObscure;
import org.witness.informacam.app.editors.image.filters.InformaTagger;
import org.witness.informacam.app.editors.image.filters.PixelizeObscure;
import org.witness.informacam.app.editors.image.filters.RegionProcesser;
import org.witness.informacam.app.editors.image.filters.SolidObscure;
import org.witness.informacam.utils.Constants.App;
import org.witness.informacam.utils.Constants.Informa.Keys.Data;

import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

public class ImageRegion implements OnActionItemClickListener {

    public static final String LOGTAG = "SSC.ImageRegion";

    // Rect for this when unscaled
    public RectF mBounds;
    //public RectF mTmpBounds;

    // Start point for touch events
    PointF mStartPoint = null;
    PointF mNonMappedStartPoint = null;

    // Our current mode
    public static final int NORMAL_MODE = 0;
    public static final int EDIT_MODE = 1;

    // The current touch event mode
    public final static int NONE = 0;
    public final static int MOVE = 1;

    // What should be done to this region
    public static final int NOTHING = 0;
    public static final int OBSCURE = 1;

    public static final int REDACT = 0; // PaintSquareObscure
    public static final int PIXELATE = 1; // PixelizeObscure
    public static final int BG_PIXELATE = 2; // BlurObscure
    public static final int CONSENT = 3; // PixelizeObscure

    boolean selected = false;

    public static final int CORNER_UPPER_LEFT = 1;
    public static final int CORNER_LOWER_LEFT = 2;
    public static final int CORNER_UPPER_RIGHT = 3;
    public static final int CORNER_LOWER_RIGHT = 4;
    public static final int CORNER_NONE = -1;

    /* Add each ObscureMethod to this list and update the 
     * createObscuredBitmap method in ImageEditor
     */
    int mObscureType = PIXELATE;

    //the other of these strings and resources determines the order in the popup menu
    private final static String[] mFilterLabels = { "Redact", "Pixelate", "CrowdPixel", "Identify" };
    private final static int[] mFilterIcons = { R.drawable.ic_context_fill, R.drawable.ic_context_pixelate,
            R.drawable.ic_context_pixelate, R.drawable.ic_context_id };

    public final Drawable unidentifiedBorder, identifiedBorder;
    public Drawable imageRegionBorder;

    // The ImageEditor object that contains us
    ImageEditor mImageEditor;

    // Popup menu for region 
    // What's the license for this?
    QuickAction mPopupMenu;

    ActionItem[] mActionFilters;

    RegionProcesser mRProc;

    private final static float MIN_MOVE = 5f;

    private final static float CORNER_MAX = 50f;

    private int cornerMode = -1;
    private long timestampOnGeneration;

    public RegionProcesser getRegionProcessor() {
        return mRProc;
    }

    public void setRegionProcessor(RegionProcesser rProc) {
        mRProc = rProc;
        Properties prop = mRProc.getProperties();
        prop.put(Data.ImageRegion.TIMESTAMP, timestampOnGeneration);
        mRProc.setProperties(prop);
    }

    public JSONObject getRepresentation() throws JSONException {
        JSONObject representation = new JSONObject();
        Enumeration<?> e = mRProc.getProperties().propertyNames();

        while (e.hasMoreElements()) {
            String prop = (String) e.nextElement();
            representation.put(prop, mRProc.getProperties().get(prop));
        }

        return representation;
    }

    public void setCornerMode(float x, float y) {
        float[] points = { x, y };
        iMatrix.mapPoints(points);

        float cSize = CORNER_MAX;

        cSize = iMatrix.mapRadius(cSize);

        if (Math.abs(mBounds.left - points[0]) < cSize && Math.abs(mBounds.top - points[1]) < cSize) {
            cornerMode = CORNER_UPPER_LEFT;
            return;
        } else if (Math.abs(mBounds.left - points[0]) < cSize && Math.abs(mBounds.bottom - points[1]) < cSize) {
            cornerMode = CORNER_LOWER_LEFT;
            return;
        } else if (Math.abs(mBounds.right - points[0]) < cSize && Math.abs(mBounds.top - points[1]) < cSize) {
            cornerMode = CORNER_UPPER_RIGHT;
            return;
        } else if (Math.abs(mBounds.right - points[0]) < cSize && Math.abs(mBounds.bottom - points[1]) < cSize) {
            cornerMode = CORNER_LOWER_RIGHT;
            return;
        }

        cornerMode = CORNER_NONE;
    }

    /* For touch events, whether or not to show the menu
     */
    boolean moved = false;

    Matrix mMatrix, iMatrix;

    int fingerCount = 0;

    public ImageRegion(ImageEditor imageEditor, float left, float top, float right, float bottom, Matrix matrix) {
        //super(imageEditor);
        super();

        // Set the mImageEditor that this region belongs to to the one passed in
        mImageEditor = imageEditor;
        // set the borders for tags in Non-Edit mode
        identifiedBorder = imageEditor.getResources().getDrawable(R.drawable.border_idtag);
        unidentifiedBorder = imageEditor.getResources().getDrawable(R.drawable.border);

        mMatrix = matrix;
        iMatrix = new Matrix();
        mMatrix.invert(iMatrix);

        mBounds = new RectF(left, top, right, bottom);

        timestampOnGeneration = System.currentTimeMillis();

        //set default processor
        this.setRegionProcessor(new PixelizeObscure());
        mImageEditor.associateImageRegionData(this);
    }

    public void setMatrix(Matrix matrix) {
        mMatrix = matrix;
        iMatrix = new Matrix();
        mMatrix.invert(iMatrix);
    }

    public void inflatePopup(boolean showDelayed) {

        if (mPopupMenu == null)
            initPopup();

        if (showDelayed) {
            // We need layout to pass again, let's wait a second or two
            new Handler() {
                @Override
                public void handleMessage(Message msg) {

                    //float[] points = {mBounds.centerX(), mBounds.centerY()};      
                    //mMatrix.mapPoints(points);

                    //mPopupMenu.show(mImageEditor.getImageView(), (int)points[0], (int)points[1]);
                    mPopupMenu.show(mImageEditor.getImageView(), (int) mBounds.centerX(), (int) mBounds.centerY());
                }
            }.sendMessageDelayed(new Message(), 300);
        } else {

            float[] points = { mBounds.centerX(), mBounds.centerY() };
            mMatrix.mapPoints(points);

            //mPopupMenu.show(mImageEditor.getImageView(), (int)points[0], (int)points[1]);
            mPopupMenu.show(mImageEditor.getImageView(), (int) mBounds.centerX(), (int) mBounds.centerY());
        }

    }

    private void initPopup() {
        mPopupMenu = new QuickAction(mImageEditor);

        ActionItem aItem;

        for (int i = 0; i < mFilterLabels.length; i++) {

            aItem = new ActionItem();
            aItem.setTitle(mFilterLabels[i]);

            aItem.setIcon(mImageEditor.getResources().getDrawable(mFilterIcons[i]));

            mPopupMenu.addActionItem(aItem);

        }

        aItem = new ActionItem();
        aItem.setTitle("Clear Tag");
        aItem.setIcon(mImageEditor.getResources().getDrawable(R.drawable.ic_context_delete));

        mPopupMenu.addActionItem(aItem);

        mPopupMenu.setOnActionItemClickListener(this);
    }

    boolean isSelected() {
        return selected;
    }

    void setSelected(boolean _selected) {
        selected = _selected;
    }

    private void updateBounds(float left, float top, float right, float bottom) {
        //Log.i(LOGTAG, "updateBounds: " + left + "," + top + "," + right + "," + bottom);
        mBounds.set(left, top, right, bottom);

        //updateLayout();
    }

    float scaleX, scaleY, leftOffset, topOffset;

    public void updateMatrix() {
        float[] mValues = new float[9];
        mMatrix.getValues(mValues);
        mMatrix.invert(iMatrix);
        scaleX = mValues[Matrix.MSCALE_X];
        scaleY = mValues[Matrix.MSCALE_Y];

        leftOffset = mValues[Matrix.MTRANS_X];
        topOffset = mValues[Matrix.MTRANS_Y];

    }

    public RectF getBounds() {
        return mBounds;
    }

    public boolean onTouch(View v, MotionEvent event) {

        fingerCount = event.getPointerCount();
        //   Log.v(LOGTAG,"onTouch: fingers=" + fingerCount);

        switch (event.getAction() & MotionEvent.ACTION_MASK) {

        case MotionEvent.ACTION_DOWN:

            mImageEditor.doRealtimePreview = true;
            mImageEditor.updateDisplayImage();
            //mTmpBounds = new RectF(mBounds);

            if (fingerCount == 1) {
                //float[] points = {event.getX(), event.getY()};                   
                //iMatrix.mapPoints(points);
                //mStartPoint = new PointF(points[0],points[1]);
                mStartPoint = new PointF(event.getX(), event.getY());
                //Log.v(LOGTAG,"startPoint: " + mStartPoint.x + " " + mStartPoint.y);
            }

            moved = false;

            return false;
        case MotionEvent.ACTION_POINTER_UP:

            Log.v(LOGTAG, "second finger removed - pointer up!");

            return moved;

        case MotionEvent.ACTION_UP:

            mImageEditor.doRealtimePreview = true;
            mImageEditor.updateDisplayImage();
            //mTmpBounds = null;

            return moved;

        case MotionEvent.ACTION_MOVE:

            if (fingerCount > 1) {

                float[] points = { event.getX(0), event.getY(0), event.getX(1), event.getY(1) };
                iMatrix.mapPoints(points);

                mStartPoint = new PointF(points[0], points[1]);

                RectF newBox = new RectF();
                newBox.left = Math.min(points[0], points[2]);
                newBox.top = Math.min(points[1], points[3]);
                newBox.right = Math.max(points[0], points[2]);
                newBox.bottom = Math.max(points[1], points[3]);

                moved = true;

                if (newBox.left != newBox.right && newBox.top != newBox.bottom) {

                    updateBounds(newBox.left, newBox.top, newBox.right, newBox.bottom);
                }

            } else if (fingerCount == 1) {

                if (Math.abs(mStartPoint.x - event.getX()) > MIN_MOVE) {
                    moved = true;

                    float[] points = { mStartPoint.x, mStartPoint.y, event.getX(), event.getY() };

                    iMatrix.mapPoints(points);

                    float diffX = points[0] - points[2];
                    float diffY = points[1] - points[3];

                    float left = 0, top = 0, right = 0, bottom = 0;

                    if (cornerMode == CORNER_NONE) {

                        left = mBounds.left - diffX;
                        top = mBounds.top - diffY;
                        right = mBounds.right - diffX;
                        bottom = mBounds.bottom - diffY;
                    } else if (cornerMode == CORNER_UPPER_LEFT) {
                        left = mBounds.left - diffX;
                        top = mBounds.top - diffY;
                        right = mBounds.right;
                        bottom = mBounds.bottom;

                    } else if (cornerMode == CORNER_LOWER_LEFT) {
                        left = mBounds.left - diffX;
                        top = mBounds.top;
                        right = mBounds.right;
                        bottom = mBounds.bottom - diffY;

                    } else if (cornerMode == CORNER_UPPER_RIGHT) {
                        left = mBounds.left;
                        top = mBounds.top - diffY;
                        right = mBounds.right - diffX;
                        bottom = mBounds.bottom;
                    } else if (cornerMode == CORNER_LOWER_RIGHT) {
                        left = mBounds.left;
                        top = mBounds.top;
                        right = mBounds.right - diffX;
                        bottom = mBounds.bottom - diffY;
                    }

                    if ((left + CORNER_MAX) > right || (top + CORNER_MAX) > bottom)
                        return false;

                    //updateBounds(Math.min(left, right), Math.min(top,bottom), Math.max(left, right), Math.max(top, bottom));
                    updateBounds(left, top, right, bottom);

                    mStartPoint = new PointF(event.getX(), event.getY());
                } else {
                    moved = false;
                }

            }

            mImageEditor.updateDisplayImage();

            return true;

        }

        return false;

    }

    public void updateRegionProcessor(int obscureType) {

        switch (obscureType) {
        case ImageRegion.BG_PIXELATE:
            Log.v(App.LOG, "obscureType: BGPIXELIZE");
            setRegionProcessor(new CrowdPixelizeObscure());
            break;
        case ImageRegion.REDACT:
            Log.v(App.LOG, "obscureType: SOLID");
            setRegionProcessor(new SolidObscure());
            break;
        case ImageRegion.PIXELATE:
            setRegionProcessor(new PixelizeObscure());
            break;
        case ImageRegion.CONSENT:
            // If the region processor is already a consent tagger, the user wants to edit.
            // so no need to change the region processor.
            if (!(getRegionProcessor() instanceof InformaTagger)) {
                setRegionProcessor(new InformaTagger());
                mImageEditor.updateDisplayImage();
            }

            mImageEditor.launchDestinationChooser(this);
            break;
        default:
            setRegionProcessor(new PixelizeObscure());
            break;
        }

        if (getRegionProcessor().getClass() == InformaTagger.class)
            imageRegionBorder = identifiedBorder;
        else
            imageRegionBorder = unidentifiedBorder;

        mImageEditor.updateDisplayImage();
    }

    @Override
    public void onItemClick(QuickAction source, int pos, int actionId) {

        if (pos == mFilterLabels.length) //meaing after the last one
        {
            mImageEditor.deleteRegion(ImageRegion.this);
        } else {
            mObscureType = pos;
            updateRegionProcessor(mObscureType);

        }

        mImageEditor.updateDisplayImage();

    }

}