import android.view.Display;
import android.view.Menu;
import android.view.MenuItem;
-import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
-import android.view.View.OnTouchListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ImageButton;
import com.android.gallery3d.filtershow.imageshow.ImageStraighten;
import com.android.gallery3d.filtershow.imageshow.ImageZoom;
import com.android.gallery3d.filtershow.presets.ImagePreset;
-import com.android.gallery3d.filtershow.presets.ImagePresetBW;
-import com.android.gallery3d.filtershow.presets.ImagePresetBWBlue;
-import com.android.gallery3d.filtershow.presets.ImagePresetBWGreen;
-import com.android.gallery3d.filtershow.presets.ImagePresetBWRed;
-import com.android.gallery3d.filtershow.presets.ImagePresetFX;
-import com.android.gallery3d.filtershow.presets.ImagePresetOld;
-import com.android.gallery3d.filtershow.presets.ImagePresetSaturated;
-import com.android.gallery3d.filtershow.presets.ImagePresetXProcessing;
import com.android.gallery3d.filtershow.provider.SharedImageProvider;
import com.android.gallery3d.filtershow.tools.SaveCopyTask;
import com.android.gallery3d.filtershow.ui.ImageCurves;
private ImageBorder mImageBorders = null;
private ImageStraighten mImageStraighten = null;
private ImageZoom mImageZoom = null;
- private ImageCrop mImageCrop = null;
+ private final ImageCrop mImageCrop = null;
private ImageRotate mImageRotate = null;
private ImageFlip mImageFlip = null;
mImageBorders = (ImageBorder) findViewById(R.id.imageBorder);
mImageStraighten = (ImageStraighten) findViewById(R.id.imageStraighten);
mImageZoom = (ImageZoom) findViewById(R.id.imageZoom);
- mImageCrop = (ImageCrop) findViewById(R.id.imageCrop);
+ // TODO: implement crop
+ // mImageCrop = (ImageCrop) findViewById(R.id.imageCrop);
mImageRotate = (ImageRotate) findViewById(R.id.imageRotate);
mImageFlip = (ImageFlip) findViewById(R.id.imageFlip);
mImageViews.add(mImageBorders);
mImageViews.add(mImageStraighten);
mImageViews.add(mImageZoom);
- mImageViews.add(mImageCrop);
+ // TODO: implement crop
+ // mImageViews.add(mImageCrop);
mImageViews.add(mImageRotate);
mImageViews.add(mImageFlip);
mImageStraighten.setMaster(mImageShow);
mImageZoom.setImageLoader(mImageLoader);
mImageZoom.setMaster(mImageShow);
- mImageCrop.setImageLoader(mImageLoader);
- mImageCrop.setMaster(mImageShow);
+ // TODO: implement crop
+ // mImageCrop.setImageLoader(mImageLoader);
+ // mImageCrop.setMaster(mImageShow);
mImageRotate.setImageLoader(mImageLoader);
mImageRotate.setMaster(mImageShow);
mImageFlip.setImageLoader(mImageLoader);
mPanelController.addImageView(findViewById(R.id.imageCurves));
mPanelController.addImageView(findViewById(R.id.imageBorder));
mPanelController.addImageView(findViewById(R.id.imageStraighten));
- mPanelController.addImageView(findViewById(R.id.imageCrop));
+ // TODO: implement crop
+ // mPanelController.addImageView(findViewById(R.id.imageCrop));
mPanelController.addImageView(findViewById(R.id.imageRotate));
mPanelController.addImageView(findViewById(R.id.imageFlip));
mPanelController.addImageView(findViewById(R.id.imageZoom));
mPanelController.addPanel(mGeometryButton, mListGeometry, 2);
mPanelController.addComponent(mGeometryButton, findViewById(R.id.straightenButton));
- mPanelController.addComponent(mGeometryButton, findViewById(R.id.cropButton));
+ // TODO: implement crop
+// mPanelController.addComponent(mGeometryButton, findViewById(R.id.cropButton));
mPanelController.addComponent(mGeometryButton, findViewById(R.id.rotateButton));
mPanelController.addComponent(mGeometryButton, findViewById(R.id.flipButton));
mUtilityPanel.setEffectName(ename);
break;
}
+ /*
+ // TODO: implement crop
case R.id.cropButton: {
mCurrentImage = showImageView(R.id.imageCrop);
String ename = mCurrentImage.getContext().getString(R.string.crop);
mUtilityPanel.showParameter(false);
break;
}
+ */
case R.id.rotateButton: {
mCurrentImage = showImageView(R.id.imageRotate);
String ename = mCurrentImage.getContext().getString(R.string.rotate);
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Matrix;
import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.util.Log;
import com.android.gallery3d.filtershow.imageshow.GeometryMetadata;
-import com.android.gallery3d.filtershow.imageshow.GeometryMetadata.FLIP;
-import com.android.gallery3d.filtershow.imageshow.ImageGeometry;
public class ImageFilterGeometry extends ImageFilter {
private final Bitmap.Config mConfig = Bitmap.Config.ARGB_8888;
native protected void nativeApplyFilterStraighten(Bitmap src, int srcWidth, int srcHeight,
Bitmap dst, int dstWidth, int dstHeight, float straightenAngle);
- @Override
- public Bitmap apply(Bitmap originalBitmap, float scaleFactor, boolean highQuality) {
- Rect cropBounds = new Rect();
- Rect originalBounds = new Rect();
- FLIP flipType = mGeometry.getFlipType();
- float rAngle = mGeometry.getRotation();
- float sAngle = mGeometry.getStraightenRotation();
- mGeometry.getCropBounds().roundOut(cropBounds);
- mGeometry.getPhotoBounds().roundOut(originalBounds);
- boolean flip = flipType != FLIP.NONE;
- boolean rotate = rAngle != 0;
- boolean crop = !cropBounds.equals(originalBounds);
- boolean straighten = sAngle != 0;
-
- int jniFlipType = 0;
- switch (flipType) {
- case BOTH:
- jniFlipType = BOTH;
- break;
- case VERTICAL:
- jniFlipType = VERTICAL;
- break;
- case HORIZONTAL:
- jniFlipType = HORIZONTAL;
- break;
- default:
- jniFlipType = 0;
- break;
- }
- int bmWidth = originalBitmap.getWidth();
- int bmHeight = originalBitmap.getHeight();
- if (!(flip || rotate || crop || straighten)) {
- return originalBitmap;
- }
- if (originalBounds.width() != bmWidth || originalBounds.height() != bmHeight) {
- if (LOGV)
- Log.v(LOGTAG, "PHOTOBOUNDS WIDTH/HEIGHT NOT SAME AS BITMAP WIDTH/HEIGHT");
- return originalBitmap;
- }
- Bitmap modBitmap = originalBitmap;
- Rect modifiedBounds = new Rect(originalBounds);
- if (flip) {
- modBitmap = originalBitmap.copy(mConfig, true);
- nativeApplyFilterFlip(originalBitmap, bmWidth, bmHeight, modBitmap,
- bmWidth, bmHeight, jniFlipType);
- }
- if (rotate) {
- // Fails for non-90 degree rotations
- Bitmap modBitmapRotate = null;
- rAngle %= 360;
- int deg = (int) (rAngle / 90);
- deg = -deg; // Make CCW positive
- if (deg < 0)
- deg += 4;
- // Now deg is in [1, 3] as required by native rotate
- if (deg == ONE_EIGHTY) {
- modBitmapRotate = Bitmap.createBitmap(bmWidth, bmHeight, mConfig);
- nativeApplyFilterRotate(modBitmap, bmWidth, bmHeight, modBitmapRotate,
- bmWidth, bmHeight, deg);
- modifiedBounds = new Rect(0, 0, bmWidth, bmHeight);
- } else if (deg == TWO_SEVENTY || deg == NINETY) {
- modBitmapRotate = Bitmap.createBitmap(bmHeight, bmWidth, mConfig);
- nativeApplyFilterRotate(modBitmap, bmWidth, bmHeight, modBitmapRotate,
- bmHeight, bmWidth, deg);
- modifiedBounds = new Rect(0, 0, bmHeight, bmWidth);
- }
- modBitmap = modBitmapRotate;
- }
- if (straighten) {
- Rect straightenBounds = new Rect();
- ImageGeometry.getUntranslatedStraightenCropBounds(new RectF(modifiedBounds), sAngle)
- .roundOut(straightenBounds);
- Bitmap modBitmapStraighten = Bitmap.createBitmap(straightenBounds.width(),
- straightenBounds.height(), mConfig);
- nativeApplyFilterStraighten(modBitmap, modifiedBounds.width(), modifiedBounds.height(),
- modBitmapStraighten,
- straightenBounds.width(), straightenBounds.height(),
- mGeometry.getStraightenRotation());
- modifiedBounds = straightenBounds;
- modBitmap = modBitmapStraighten;
+ public Matrix buildMatrix(Bitmap bitmap, boolean rotated) {
+ Matrix drawMatrix = new Matrix();
+ float dx = bitmap.getWidth() / 2.0f;
+ float dy = bitmap.getHeight() / 2.0f;
+
+ Matrix flipper = mGeometry.getFlipMatrix(bitmap.getWidth(), bitmap.getHeight());
+ drawMatrix.postConcat(flipper);
+ drawMatrix.postTranslate(-dx, -dy);
+ drawMatrix.postScale(1.0f / mGeometry.getScaleFactor(), 1.0f / mGeometry.getScaleFactor());
+ float angle = (mGeometry.getRotation() + mGeometry.getStraightenRotation());
+ drawMatrix.postRotate(angle);
+ if (rotated) {
+ drawMatrix.postTranslate(dy, dx);
+ } else {
+ drawMatrix.postTranslate(dx, dy);
}
- if (crop) {
- Bitmap modBitmapCrop = Bitmap.createBitmap(cropBounds.width(), cropBounds.height(),
- mConfig);
- // Force crop bounds to be within straighten bounds.
- if (!modifiedBounds.intersect(cropBounds)) {
- return modBitmap;
- }
- nativeApplyFilterCrop(modBitmap, bmWidth, bmHeight, modBitmapCrop,
- cropBounds.width(), cropBounds.height(), cropBounds.left, cropBounds.top);
- modBitmap = modBitmapCrop;
+ return drawMatrix;
+ }
+
+ @Override
+ public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
+ // TODO: implement bilinear or bicubic here... for now, just use
+ // canvas to do a simple implementation...
+ // TODO: and be more memory efficient! (do it in native?)
+
+ Bitmap temp = null;
+ float rotation = mGeometry.getRotation();
+ boolean rotated = false;
+ if (rotation == 0 || rotation % 180 == 0) {
+ temp = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), mConfig);
+ } else {
+ temp = Bitmap.createBitmap(bitmap.getHeight(), bitmap.getWidth(), mConfig);
+ rotated = true;
}
- return modBitmap;
+
+ Matrix drawMatrix = buildMatrix(bitmap, rotated);
+ Canvas canvas = new Canvas(temp);
+ canvas.drawBitmap(bitmap, drawMatrix, new Paint());
+ return temp;
}
}
package com.android.gallery3d.filtershow.imageshow;
import android.graphics.Bitmap;
+import android.graphics.Matrix;
import android.graphics.RectF;
import com.android.gallery3d.filtershow.filters.ImageFilterGeometry;
// Applied in order: rotate, crop, scale.
// Do not scale saved image (presumably?).
private static final ImageFilterGeometry mImageFilter = new ImageFilterGeometry();
- private float mScaleFactor = 0;
+ private float mScaleFactor = 1.0f;
private float mRotation = 0;
private float mStraightenRotation = 0;
private final RectF mCropBounds = new RectF();
private FLIP mFlip = FLIP.NONE;
private boolean mSafe = false;
+ private Matrix mMatrix = new Matrix();
+
+ private RectF mBounds = new RectF();
+
public enum FLIP {
NONE, VERTICAL, HORIZONTAL, BOTH
}
public Bitmap apply(Bitmap original, float scaleFactor, boolean highQuality){
mImageFilter.setGeometryMetadata(this);
Bitmap m = mImageFilter.apply(original, scaleFactor, highQuality);
- mPhotoBounds.set(0,0, m.getWidth(), m.getHeight());
- mCropBounds.set(mPhotoBounds);
- mScaleFactor = 0;
- mRotation = 0;
- mStraightenRotation = 0;
- mFlip = FLIP.NONE;
- mSafe = false;
return m;
}
- public GeometryMetadata(float scale, float rotation, float straighten, RectF cropBounds,
- RectF photoBounds, FLIP flipType) {
- mScaleFactor = scale;
- mRotation = rotation;
- mStraightenRotation = straighten;
- mCropBounds.set(cropBounds);
- mPhotoBounds.set(photoBounds);
- mFlip = flipType;
- mSafe = cropFitsInPhoto(mCropBounds);
- }
-
// Safe as long as invariant holds.
public void set(GeometryMetadata g) {
mScaleFactor = g.mScaleFactor;
mPhotoBounds.set(g.mPhotoBounds);
mFlip = g.mFlip;
mSafe = g.mSafe;
- }
-
- public void safeSet(GeometryMetadata g) {
- if (g.safe()) {
- set(g);
- return;
- }
-
- mScaleFactor = g.mScaleFactor;
- mRotation = g.mRotation;
- mStraightenRotation = g.mStraightenRotation;
- mCropBounds.set(g.mCropBounds);
- safeSetPhotoBounds(g.mPhotoBounds);
- mFlip = g.mFlip;
- }
-
- public void safeSet(float scale,
- float rotation,
- float straighten,
- RectF cropBounds,
- RectF photoBounds,
- FLIP flipType) {
- mScaleFactor = scale;
- mStraightenRotation = straighten;
- mRotation = rotation;
- mCropBounds.set(cropBounds);
- safeSetPhotoBounds(photoBounds);
- mFlip = flipType;
+ mMatrix = g.mMatrix;
+ mBounds = g.mBounds;
}
public float getScaleFactor() {
+ ",photoRect=" + mPhotoBounds.toShortString() + "]";
}
+ protected Matrix getHorizontalMatrix(float width) {
+ Matrix flipHorizontalMatrix = new Matrix();
+ flipHorizontalMatrix.setScale(-1, 1);
+ flipHorizontalMatrix.postTranslate(width, 0);
+ return flipHorizontalMatrix;
+ }
+
+ protected Matrix getVerticalMatrix(float height) {
+ Matrix flipVerticalMatrix = new Matrix();
+ flipVerticalMatrix.setScale(1, -1);
+ flipVerticalMatrix.postTranslate(0, height);
+ return flipVerticalMatrix;
+ }
+
+ public Matrix getFlipMatrix(float width, float height) {
+ FLIP type = getFlipType();
+ if (type == FLIP.HORIZONTAL) {
+ return getHorizontalMatrix(width);
+ } else if (type == FLIP.VERTICAL) {
+ return getVerticalMatrix(height);
+ } else if (type == FLIP.BOTH) {
+ Matrix flipper = getVerticalMatrix(height);
+ flipper.postConcat(getHorizontalMatrix(width));
+ return flipper;
+ } else {
+ Matrix m = new Matrix();
+ m.reset(); // identity
+ return m;
+ }
+ }
+
+ public Matrix getMatrix() {
+ return mMatrix;
+ }
}
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
-import android.graphics.PointF;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
-import android.view.MotionEvent;
-import com.android.gallery3d.R;
-import com.android.gallery3d.filtershow.presets.ImagePreset;
+import com.android.gallery3d.R;
public class ImageCrop extends ImageGeometry {
private static final boolean LOGV = false;
private static final int TOUCH_TOLERANCE = 30;
private static final int SHADOW_ALPHA = 160;
- private float mAspectWidth = 4;
- private float mAspectHeight = 3;
- private boolean mFixAspectRatio = false; // not working yet
+ private final float mAspectWidth = 4;
+ private final float mAspectHeight = 3;
+ private final boolean mFixAspectRatio = false; // not working yet
private final Paint borderPaint;
return m;
}
+ @Override
protected RectF getCropBoundsDisplayed() {
RectF bounds = getLocalCropBounds();
RectF crop = new RectF(bounds);
cbounds.set(cbounds.left, cbounds.top, cbounds.left + newWidth, cbounds.top + newHeight);
RectF snappedCrop = findCropBoundForRotatedImg(cbounds, pbounds, getLocalStraighten(),
mCenterX - mXOffset, mCenterY - mYOffset);
+
+ RectF straightenBounds = getUntranslatedStraightenCropBounds(getLocalPhotoBounds(), getLocalStraighten());
+ snappedCrop.intersect(straightenBounds);
+
+
if (mFixAspectRatio) {
// TODO: add aspect ratio stuff
fixAspectRatio(snappedCrop, mAspectWidth, mAspectHeight);
}
}
- private void drawShadow(Canvas canvas, float left, float top, float right, float bottom) {
- canvas.save();
- canvas.clipRect(left, top, right, bottom);
- canvas.drawARGB(SHADOW_ALPHA, 0, 0, 0);
- canvas.restore();
- }
-
private void drawIndicator(Canvas canvas, Drawable indicator, float centerX, float centerY) {
int left = (int) centerX - indicatorSize / 2;
int top = (int) centerY - indicatorSize / 2;
@Override
protected void gainedVisibility() {
setCropBounds(getLocalCropBounds());
+ super.gainedVisibility();
}
- @Override
- protected void lostVisibility() {
+ protected RectF drawCrop(Canvas canvas, Paint p, RectF cropBounds, float scale,
+ float rotation, float centerX, float centerY, float offsetX, float offsetY) {
+ RectF crop = new RectF(cropBounds);
+ Matrix m = new Matrix();
+ m.preTranslate(offsetX, offsetY);
+ m.mapRect(crop);
+
+ m.setRotate(rotation, centerX, centerY);
+ if (!m.rectStaysRect()) {
+ float[] corners = getCornersFromRect(crop);
+ m.mapPoints(corners);
+ drawClosedPath(canvas, p, corners);
+ } else {
+ RectF crop2 = new RectF(crop);
+ m.mapRect(crop2);
+ Path path = new Path();
+ path.addRect(crop2, Path.Direction.CCW);
+ canvas.drawPath(path, p);
+ }
+ return crop;
}
@Override
gPaint.setFilterBitmap(true);
gPaint.setDither(true);
gPaint.setARGB(255, 255, 255, 255);
+ drawTransformedBitmap(canvas, image, gPaint, false);
- drawRegularFlippedBitmap(canvas, image, gPaint);
-
- RectF displayRect = getLocalDisplayBounds();
- float dWidth = displayRect.width();
- float dHeight = displayRect.height();
- RectF boundsRect = getCropBoundsDisplayed();
- gPaint.setARGB(128, 0, 0, 0);
- gPaint.setStyle(Paint.Style.FILL);
- // TODO: move this to style when refactoring
- canvas.drawRect(0, 0, dWidth, boundsRect.top, gPaint);
- canvas.drawRect(0, boundsRect.bottom, dWidth, dHeight, gPaint);
- canvas.drawRect(0, boundsRect.top, boundsRect.left, boundsRect.bottom,
- gPaint);
- canvas.drawRect(boundsRect.right, boundsRect.top, dWidth,
- boundsRect.bottom, gPaint);
-
- Path path = new Path();
- path.addRect(boundsRect, Path.Direction.CCW);
- gPaint.setARGB(255, 255, 255, 255);
- gPaint.setStrokeWidth(3);
- gPaint.setStyle(Paint.Style.STROKE);
+ float scale = getLocalScale();
+ float rotation = getLocalRotation();
- canvas.drawPath(path, gPaint);
+ RectF scaledCrop = drawCrop(canvas, gPaint, getLocalCropBounds(), scale,
+ rotation, mCenterX, mCenterY, mXOffset,
+ mYOffset);
boolean notMoving = movingEdges == 0;
if (((movingEdges & MOVE_TOP) != 0) || notMoving) {
- drawIndicator(canvas, cropIndicator, boundsRect.centerX(), boundsRect.top);
+ drawIndicator(canvas, cropIndicator, scaledCrop.centerX(), scaledCrop.top);
}
if (((movingEdges & MOVE_BOTTOM) != 0) || notMoving) {
- drawIndicator(canvas, cropIndicator, boundsRect.centerX(), boundsRect.bottom);
+ drawIndicator(canvas, cropIndicator, scaledCrop.centerX(), scaledCrop.bottom);
}
if (((movingEdges & MOVE_LEFT) != 0) || notMoving) {
- drawIndicator(canvas, cropIndicator, boundsRect.left, boundsRect.centerY());
+ drawIndicator(canvas, cropIndicator, scaledCrop.left, scaledCrop.centerY());
}
if (((movingEdges & MOVE_RIGHT) != 0) || notMoving) {
- drawIndicator(canvas, cropIndicator, boundsRect.right, boundsRect.centerY());
+ drawIndicator(canvas, cropIndicator, scaledCrop.right, scaledCrop.centerY());
}
}
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.Matrix;
import android.graphics.Paint;
-import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
gPaint.setFilterBitmap(true);
gPaint.setDither(true);
gPaint.setARGB(255, 255, 255, 255);
-
- FLIP flip = mNextFlip;
- canvas.save();
- float zoom = getLocalScale();
- canvas.rotate(getTotalLocalRotation(), mCenterX, mCenterY);
- canvas.scale(zoom, zoom, mCenterX, mCenterY);
- canvas.translate(mXOffset, mYOffset);
- if (flip == FLIP.HORIZONTAL) {
- Matrix flipper = getHorizontalMatrix(image.getWidth());
- canvas.drawBitmap(image, flipper, gPaint);
- } else if (flip == FLIP.VERTICAL) {
- Matrix flipper = getVerticalMatrix(image.getHeight());
- canvas.drawBitmap(image, flipper, gPaint);
- } else if (flip == FLIP.BOTH) {
- Matrix flipper = getVerticalMatrix(image.getHeight());
- flipper.postConcat(getHorizontalMatrix(image.getWidth()));
- canvas.drawBitmap(image, flipper, gPaint);
- } else {
- canvas.drawBitmap(image, 0, 0, gPaint);
- }
- canvas.restore();
-
- RectF cropBounds = getCropBoundsDisplayed(getLocalCropBounds());
-
- Matrix m0 = new Matrix();
- m0.setRotate(getLocalRotation(), mCenterX, mCenterY);
- float[] corners = getCornersFromRect(cropBounds);
- m0.mapPoints(corners);
- gPaint.setARGB(255, 255, 255, 255);
- // TODO: pull out style to xml
- gPaint.setStrokeWidth(3);
- gPaint.setStyle(Paint.Style.STROKE);
- drawClosedPath(canvas, gPaint, corners);
-
- canvas.save();
- canvas.rotate(getLocalRotation(), mCenterX, mCenterY);
- RectF displayRect = getLocalDisplayBounds();
- float dWidth = displayRect.width();
- float dHeight = displayRect.height();
- RectF boundsRect = cropBounds;
- gPaint.setARGB(128, 0, 0, 0);
- gPaint.setStyle(Paint.Style.FILL);
- canvas.drawRect(0, 0, dWidth, boundsRect.top, gPaint);
- canvas.drawRect(0, boundsRect.bottom, dWidth, dHeight, gPaint);
- canvas.drawRect(0, boundsRect.top, boundsRect.left, boundsRect.bottom,
- gPaint);
- canvas.drawRect(boundsRect.right, boundsRect.top, dWidth,
- boundsRect.bottom, gPaint);
- canvas.rotate(-getLocalRotation(), mCenterX, mCenterY);
- canvas.restore();
+ drawTransformedBitmap(canvas, image, gPaint, false);
}
+
}
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
+import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
protected float mTouchCenterX;
protected float mTouchCenterY;
+ private Matrix mLocalMatrix = null;
+
// Local geometry data
private GeometryMetadata mLocalGeoMetadata = null;
private RectF mLocalDisplayBounds = null;
calculateLocalScalingFactorAndOffset();
}
+ private float computeScale(float width, float height) {
+ float imageWidth = mLocalGeoMetadata.getPhotoBounds().width();
+ float imageHeight = mLocalGeoMetadata.getPhotoBounds().height();
+ float zoom = width / imageWidth;
+ if (imageHeight > imageWidth) {
+ zoom = height / imageHeight;
+ }
+ return zoom;
+ }
+
private void calculateLocalScalingFactorAndOffset() {
if (mLocalGeoMetadata == null || mLocalDisplayBounds == null)
return;
mCenterX = displayWidth / 2;
mCenterY = displayHeight / 2;
- float zoom = displayWidth / imageWidth;
- if (imageHeight > imageWidth) {
- zoom = displayHeight / imageHeight;
- }
mYOffset = (displayHeight - imageHeight) / 2.0f;
mXOffset = (displayWidth - imageWidth) / 2.0f;
+
+ float zoom = computeScale(mLocalDisplayBounds.width(), mLocalDisplayBounds.height());
mLocalGeoMetadata.setScaleFactor(zoom);
}
invalidate();
}
- private GeometryMetadata getMasterImageGeometryMetadataCopy() {
- return getMaster().getGeometry();
- }
-
// Overwrites local with master
protected void syncLocalToMasterGeometry() {
- mLocalGeoMetadata = getMasterImageGeometryMetadataCopy();
+ mLocalGeoMetadata = getMaster().getGeometry();
calculateLocalScalingFactorAndOffset();
+ mLocalMatrix = mLocalGeoMetadata.getMatrix();
+ }
+
+ public Matrix getLocalMatrix() {
+ return mLocalMatrix;
}
protected RectF getLocalPhotoBounds() {
mLocalGeoMetadata.setScaleFactor(s);
}
+ protected void updateMatrix() {
+ RectF bounds = getUntranslatedStraightenCropBounds(mLocalGeoMetadata.getPhotoBounds(),
+ getLocalStraighten());
+ float zoom = computeScale(bounds.width(), bounds.height());
+ setLocalScale(zoom);
+ float w = mLocalGeoMetadata.getPhotoBounds().width();
+ float h = mLocalGeoMetadata.getPhotoBounds().height();
+ float ratio = h / w;
+ float rcenterx = 0.5f;
+ float rcentery = 0.5f * ratio;
+ Matrix flipper = mLocalGeoMetadata.getFlipMatrix(1.0f, ratio);
+ mLocalMatrix.reset();
+ mLocalMatrix.postConcat(flipper);
+ mLocalMatrix.postRotate(getTotalLocalRotation(), rcenterx, rcentery);
+ invalidate();
+ }
+
protected void setLocalRotation(float r) {
mLocalGeoMetadata.setRotation(r);
+ updateMatrix();
}
protected void setLocalStraighten(float r) {
mLocalGeoMetadata.setStraightenRotation(r);
+ updateMatrix();
}
protected void setLocalCropBounds(RectF c) {
protected void setLocalFlip(FLIP flip) {
mLocalGeoMetadata.setFlipType(flip);
+ updateMatrix();
}
protected float getTotalLocalRotation() {
return getMaster().mForegroundImage;
}
- protected static Matrix getHorizontalMatrix(int width) {
- Matrix flipHorizontalMatrix = new Matrix();
- flipHorizontalMatrix.setScale(-1, 1);
- flipHorizontalMatrix.postTranslate(width, 0);
- return flipHorizontalMatrix;
- }
-
- protected static Matrix getVerticalMatrix(int height) {
- Matrix flipVerticalMatrix = new Matrix();
- flipVerticalMatrix.setScale(1, -1);
- flipVerticalMatrix.postTranslate(0, height);
- return flipVerticalMatrix;
- }
-
- protected static Matrix getFlipMatrix(FLIP type, int width, int height) {
- if (type == FLIP.HORIZONTAL) {
- return getHorizontalMatrix(width);
- } else if (type == FLIP.VERTICAL) {
- return getVerticalMatrix(height);
- } else if (type == FLIP.BOTH) {
- Matrix flipper = getVerticalMatrix(height);
- flipper.postConcat(getHorizontalMatrix(width));
- return flipper;
- } else {
- Matrix m = new Matrix();
- m.reset(); // identity
- return m;
- }
- }
-
- protected static float clamp(float i, float low, float high) {
- return Math.max(Math.min(i, high), low);
- }
-
protected static float[] getCornersFromRect(RectF r) {
// Order is:
// 0------->1
r.right, r.top, // 1
r.right, r.bottom,// 2
r.left, r.bottom
- };// 3
+ // 3
+ };
return corners;
}
return height * w / h;
}
+ protected void logMasterGeo() {
+ Log.v(LOGTAG, getMaster().getGeometry().toString());
+ }
+
@Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
mVisibilityGained = true;
syncLocalToMasterGeometry();
gainedVisibility();
+ logMasterGeo();
} else {
if (mVisibilityGained == true && mHasDrawn == true) {
lostVisibility();
+ logMasterGeo();
}
mVisibilityGained = false;
mHasDrawn = false;
protected void gainedVisibility() {
// TODO: Override this stub.
+ updateMatrix();
}
protected void lostVisibility() {
case (MotionEvent.ACTION_UP):
setActionUp();
saveAndSetPreset();
+ Log.v(LOGTAG, "up action");
+ logMasterGeo();
break;
case (MotionEvent.ACTION_MOVE):
setActionMove(event.getX(), event.getY());
setNoAction();
}
if (getPanelController() != null) {
- getPanelController().onNewValue((int) getLocalValue());
+ getPanelController().onNewValue(getLocalValue());
}
invalidate();
return true;
protected void saveAndSetPreset() {
ImagePreset copy = new ImagePreset(getImagePreset());
copy.setGeometry(mLocalGeoMetadata);
+ copy.setHistoryName("Geometry");
+ copy.setIsFx(false);
setImagePreset(copy);
}
- @Override
- public void updateImage() {
- }
-
- protected void drawRegularFlippedBitmap(Canvas canvas, Bitmap image, Paint p) {
- float zoom = getLocalScale();
- canvas.save();
- canvas.rotate(getTotalLocalRotation(), mCenterX, mCenterY);
- canvas.scale(zoom, zoom, mCenterX, mCenterY);
- canvas.translate(mXOffset, mYOffset);
- Matrix flipper = getFlipMatrix(getLocalFlip(), image.getWidth(), image.getHeight());
- canvas.drawBitmap(image, flipper, p);
- canvas.restore();
- }
-
- protected void drawRegularBitmap(Canvas canvas, Bitmap image, Paint p) {
- float zoom = getLocalScale();
- canvas.save();
- canvas.rotate(getTotalLocalRotation(), mCenterX, mCenterY);
- canvas.scale(zoom, zoom, mCenterX, mCenterY);
- canvas.translate(mXOffset, mYOffset);
- canvas.drawBitmap(image, 0, 0, p);
- canvas.restore();
- }
-
- protected RectF getCropBoundsDisplayed() {
- return getCropBoundsDisplayed(getLocalCropBounds());
- }
-
- protected RectF getCropBoundsDisplayed(RectF bounds) {
- RectF crop = new RectF(bounds);
- Matrix m = new Matrix();
- float zoom = getLocalScale();
- m.setScale(zoom, zoom, mCenterX, mCenterY);
- m.preTranslate(mXOffset, mYOffset);
- m.mapRect(crop);
- return crop;
- }
-
- protected static float[] correctAngles(float rotation, float straighten) {
- float[] ret = {
- rotation, straighten
- };
- if (straighten >= MIN_STRAIGHTEN_ANGLE && straighten <= MAX_STRAIGHTEN_ANGLE
- && (rotation % 90 == 0)) {
- return ret;
- }
- float remainder = rotation % 90;
- float newRot = (int) (rotation / 90);
- float tempStraighten = straighten + remainder;
- newRot += (int) (tempStraighten / 90);
- tempStraighten %= 90;
- if (tempStraighten > MAX_STRAIGHTEN_ANGLE) {
- tempStraighten -= 90;
- newRot += 1;
- } else if (tempStraighten < MIN_STRAIGHTEN_ANGLE) {
- tempStraighten += 90;
- newRot -= 1;
- }
- ret[0] = newRot * 90;
- ret[1] = tempStraighten;
- return ret;
- }
-
- protected void correctStraightenRotateAngles() {
- float straighten = getLocalStraighten();
- float rotation = getLocalRotation();
- float[] angles = correctAngles(rotation, straighten);
- setLocalStraighten(angles[1]);
- setLocalRotation(angles[0]);
- }
-
- protected static Matrix getCropRotationMatrix(float rotation) {
- Matrix m = new Matrix();
- m.setRotate(rotation);
- if (!m.rectStaysRect()) {
- return null;
- }
- return m;
- }
-
- protected RectF getStraightenCropBounds() {
- RectF imageRect = getLocalPhotoBounds();
- Matrix m = new Matrix();
- float lRot = getLocalRotation();
- m.setRotate(lRot);
- if (!m.rectStaysRect()) {
- correctStraightenRotateAngles();
- m.setRotate(getLocalRotation());
- }
- RectF crop = getStraightenCropBounds(imageRect, getLocalStraighten());
- setLocalCropBounds(crop);
- if (!m.mapRect(crop)) {
- return null;
- }
- return crop;
- }
-
- protected RectF getStraightenCropBounds(RectF imageRect, float straightenAngle) {
- RectF boundsRect = getUntranslatedStraightenCropBounds(imageRect, straightenAngle);
- RectF nonRotateImage = getLocalPhotoBounds();
- Matrix m1 = new Matrix();
- m1.setTranslate(nonRotateImage.centerX() - boundsRect.centerX(), nonRotateImage.centerY()
- - boundsRect.centerY());
- m1.mapRect(boundsRect);
- return boundsRect;
+ //
+ protected static float clamp(float i, float low, float high) {
+ return Math.max(Math.min(i, high), low);
}
public static RectF getUntranslatedStraightenCropBounds(RectF imageRect, float straightenAngle) {
return new RectF(left, top, right, bottom);
}
+ protected static void drawShadows(Canvas canvas, Paint p, RectF innerBounds, RectF outerBounds,
+ float rotation, float centerX, float centerY) {
+ canvas.save();
+ canvas.rotate(rotation, centerX, centerY);
+ float dWidth = outerBounds.width();
+ float dHeight = outerBounds.height();
+ canvas.drawRect(0, 0, dWidth, innerBounds.top, p);
+ canvas.drawRect(0, innerBounds.bottom, dWidth, dHeight, p);
+ canvas.drawRect(0, innerBounds.top, innerBounds.left, innerBounds.bottom,
+ p);
+ canvas.drawRect(innerBounds.right, innerBounds.top, dWidth,
+ innerBounds.bottom, p);
+ canvas.rotate(-rotation, centerX, centerY);
+ canvas.restore();
+ }
+
+ public Matrix computeBoundsMatrix(Bitmap bitmap) {
+ Matrix boundsMatrix = new Matrix();
+ boundsMatrix.setTranslate((getWidth() - bitmap.getWidth()) / 2.0f,
+ (getHeight() - bitmap.getHeight()) / 2.0f);
+ boundsMatrix.postRotate(getLocalRotation(), getWidth() / 2.0f, getHeight() / 2.0f);
+ return boundsMatrix;
+ }
+
+ public RectF cropBounds(Bitmap bitmap) {
+ Matrix boundsMatrix = computeBoundsMatrix(bitmap);
+ RectF bounds = getUntranslatedStraightenCropBounds(getLocalPhotoBounds(),
+ getLocalStraighten());
+ RectF transformedBounds = new RectF(bounds);
+ boundsMatrix.mapRect(transformedBounds);
+ return transformedBounds;
+ }
+
+ protected void drawTransformedBitmap(Canvas canvas, Bitmap bitmap, Paint paint, boolean clip) {
+ Matrix boundsMatrix = computeBoundsMatrix(bitmap);
+ RectF bounds = getUntranslatedStraightenCropBounds(getLocalPhotoBounds(),
+ getLocalStraighten());
+ RectF transformedBounds = new RectF(bounds);
+ boundsMatrix.mapRect(transformedBounds);
+
+ canvas.save();
+ Matrix matrix = getLocalMatrix();
+ canvas.translate((getWidth() - bitmap.getWidth()) / 2.0f,
+ (getHeight() - bitmap.getHeight()) / 2.0f);
+ paint.setARGB(255, 0, 0, 0);
+ Matrix drawMatrix = new Matrix();
+ float w = bitmap.getWidth();
+ drawMatrix.preScale(1.0f/w, 1.0f/w);
+ drawMatrix.postConcat(matrix);
+ drawMatrix.postScale(w, w);
+ canvas.drawBitmap(bitmap, drawMatrix, paint);
+ canvas.restore();
+
+ canvas.save();
+ canvas.setMatrix(boundsMatrix);
+ paint.setColor(Color.WHITE);
+ paint.setStyle(Style.STROKE);
+ paint.setStrokeWidth(2);
+ canvas.drawRect(bounds, paint);
+ canvas.restore();
+
+ if (!clip) { // we display the rest of the bitmap grayed-out
+ drawShadows(canvas, transformedBounds, new RectF(0, 0, getWidth(), getHeight()), paint);
+ }
+ }
+
+ protected RectF getCropBoundsDisplayed() {
+ return getCropBoundsDisplayed(getLocalCropBounds());
+ }
+
+ protected RectF getCropBoundsDisplayed(RectF bounds) {
+ RectF crop = new RectF(bounds);
+ Matrix m = new Matrix();
+ float zoom = getLocalScale();
+ m.setScale(zoom, zoom, mCenterX, mCenterY);
+ m.preTranslate(mXOffset, mYOffset);
+ m.mapRect(crop);
+ return crop;
+ }
+
protected void drawShadows(Canvas canvas, RectF innerBounds, RectF outerBounds, Paint p) {
float dWidth = outerBounds.width();
float dHeight = outerBounds.height();
+
+ // TODO: move style to xml
+ p.setARGB(128, 0, 0, 0);
+ p.setStyle(Paint.Style.FILL);
+
canvas.drawRect(0, 0, dWidth, innerBounds.top, p);
canvas.drawRect(0, innerBounds.bottom, dWidth, dHeight, p);
canvas.drawRect(0, innerBounds.top, innerBounds.left, innerBounds.bottom,
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.Matrix;
import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.RectF;
import android.util.AttributeSet;
-import android.util.Log;
public class ImageRotate extends ImageGeometry {
private static final float MATH_PI = (float) Math.PI;
private float mBaseAngle = 0;
private float mAngle = 0;
- private RectF mLocalBoundsCopy = null;
- private boolean mSnapToNinety = true;
+ private final boolean mSnapToNinety = true;
private static final String LOGTAG = "ImageRotate";
public ImageRotate(Context context, AttributeSet attrs) {
}
@Override
- public void resetParameter() {
- super.resetParameter();
- mLocalBoundsCopy = getLocalCropBounds();
- }
-
- @Override
- protected void gainedVisibility() {
- mLocalBoundsCopy = getLocalCropBounds();
- }
-
- @Override
- protected void lostVisibility() {
- }
-
- @Override
protected int getLocalValue() {
return (int) getLocalRotation();
}
gPaint.setFilterBitmap(true);
gPaint.setDither(true);
gPaint.setARGB(255, 255, 255, 255);
-
- drawRegularFlippedBitmap(canvas, image, gPaint);
-
- RectF cropBounds = getCropBoundsDisplayed(mLocalBoundsCopy);
-
- Matrix m0 = new Matrix();
- m0.setRotate(getLocalRotation(), mCenterX, mCenterY);
- float[] corners = getCornersFromRect(cropBounds);
- m0.mapPoints(corners);
-
- gPaint.setARGB(255, 255, 255, 255);
- gPaint.setStrokeWidth(3);
- gPaint.setStyle(Paint.Style.STROKE);
- drawClosedPath(canvas, gPaint, corners);
-
- canvas.save();
- canvas.rotate(getLocalRotation(), mCenterX, mCenterY);
- RectF displayRect = getLocalDisplayBounds();
- float dWidth = displayRect.width();
- float dHeight = displayRect.height();
- RectF boundsRect = cropBounds;
- gPaint.setARGB(128, 0, 0, 0);
- // TODO: move style to xml
- gPaint.setStyle(Paint.Style.FILL);
- canvas.drawRect(0, 0, dWidth, boundsRect.top, gPaint);
- canvas.drawRect(0, boundsRect.bottom, dWidth, dHeight, gPaint);
- canvas.drawRect(0, boundsRect.top, boundsRect.left, boundsRect.bottom,
- gPaint);
- canvas.drawRect(boundsRect.right, boundsRect.top, dWidth,
- boundsRect.bottom, gPaint);
- canvas.rotate(-getLocalRotation(), mCenterX, mCenterY);
- canvas.restore();
-
+ drawTransformedBitmap(canvas, image, gPaint, true);
}
-
}
private boolean mDirtyGeometry = true;
private Bitmap mBackgroundImage = null;
+ // TODO: remove protected here, it should be private
protected Bitmap mForegroundImage = null;
protected Bitmap mFilteredImage = null;
return mImagePreset;
}
- public Bitmap getOriginalFrontBitmap() {
+ protected Bitmap getOriginalFrontBitmap() {
if (mImageLoader != null) {
return mImageLoader.getOriginalBitmapLarge();
}
}
}
- protected void setDirtyGeometryFlag() {
+ private void setDirtyGeometryFlag() {
mDirtyGeometry = true;
}
return;
float w = image.getWidth();
float h = image.getHeight();
+ GeometryMetadata geo = getImagePreset().mGeoData;
+ RectF pb = geo.getPhotoBounds();
+ if (w == pb.width() && h == pb.height()) {
+ return;
+ }
RectF r = new RectF(0, 0, w, h);
getImagePreset().mGeoData.setPhotoBounds(r);
getImagePreset().mGeoData.setCropBounds(r);
public void updateImage() {
mForegroundImage = getOriginalFrontBitmap();
imageSizeChanged(mForegroundImage); // TODO: should change to filtered
+ setDirtyGeometryFlag();
}
public void updateFilteredImage(Bitmap bitmap) {
}
@Override
- public Bitmap getOriginalFrontBitmap() {
+ public void updateImage() {
+ // We don't want to warn listeners here that the image size has changed, because
+ // we'll be working with the small image...
+ mForegroundImage = getOriginalFrontBitmap();
+ }
+
+ @Override
+ protected Bitmap getOriginalFrontBitmap() {
if (mImageLoader == null) {
return null;
}
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
-import android.view.MotionEvent;
-
-import com.android.gallery3d.filtershow.presets.ImagePreset;
public class ImageStraighten extends ImageGeometry {
}
@Override
- protected void gainedVisibility() {
- correctStraightenRotateAngles();
- }
-
- @Override
protected void lostVisibility() {
saveAndSetPreset();
}
@Override
protected void drawShape(Canvas canvas, Bitmap image) {
- gPaint.setAntiAlias(true);
- gPaint.setFilterBitmap(true);
- gPaint.setDither(true);
- gPaint.setARGB(255, 255, 255, 255);
+ drawTransformedBitmap(canvas, image, gPaint, false);
- // Draw fully rotated image.
- drawRegularFlippedBitmap(canvas, image, gPaint);
-
- // Get cropping frame
- RectF boundsRect = getStraightenCropBounds();
-
- Matrix m1 = new Matrix();
- float zoom = getLocalScale();
- // Center and scale
- m1.setScale(zoom, zoom, mCenterX, mCenterY);
- m1.preTranslate(mCenterX - boundsRect.centerX(), mCenterY - boundsRect.centerY());
- m1.mapRect(boundsRect);
- RectF displayRect = getLocalDisplayBounds();
- float dWidth = displayRect.width();
- float dHeight = displayRect.height();
-
- // Draw shadows
- gPaint.setARGB(128, 0, 0, 0);
- gPaint.setStyle(Paint.Style.FILL);
-
- // TODO: move to xml file
- canvas.drawRect(0, 0, dWidth, boundsRect.top, gPaint);
- canvas.drawRect(0, boundsRect.bottom, dWidth, dHeight, gPaint);
- canvas.drawRect(0, boundsRect.top, boundsRect.left, boundsRect.bottom,
- gPaint);
- canvas.drawRect(boundsRect.right, boundsRect.top, dWidth,
- boundsRect.bottom, gPaint);
-
- // Draw crop frame
+ // Draw the grid
+ RectF bounds = cropBounds(image);
Path path = new Path();
- path.addRect(boundsRect, Path.Direction.CCW);
+ path.addRect(bounds, Path.Direction.CCW);
gPaint.setARGB(255, 255, 255, 255);
gPaint.setStrokeWidth(3);
- gPaint.setStyle(Paint.Style.STROKE);
- canvas.drawPath(path, gPaint);
-
gPaint.setStyle(Paint.Style.FILL_AND_STROKE);
- // Draw grid
+ RectF display = getLocalDisplayBounds();
+ float dWidth = display.width();
+ float dHeight = display.height();
+
if (mMode == MODES.MOVE) {
canvas.save();
canvas.clipPath(path);
+
int n = 16;
float step = dWidth / n;
float p = 0;
mHistoryName = name;
}
- private void setHistoryName(String name) {
+ public void setHistoryName(String name) {
mHistoryName = name;
}