Loading src/com/android/gallery3d/filtershow/PanelController.java +5 −74 Original line number Diff line number Diff line Loading @@ -139,14 +139,7 @@ public class PanelController implements OnClickListener { private boolean mShowParameterValue = false; private View mAspectButton = null; private View mCurvesButton = null; private int mCurrentAspectButton = 0; private static final int NUMBER_OF_ASPECT_BUTTONS = 6; private static final int ASPECT_NONE = 0; private static final int ASPECT_1TO1 = 1; private static final int ASPECT_5TO7 = 2; private static final int ASPECT_4TO6 = 3; private static final int ASPECT_16TO9 = 4; private static final int ASPECT_ORIG = 5; boolean firstTimeCropDisplayed = true; public UtilityPanel(Context context, View view, View textView, View aspectButton, View curvesButton) { Loading Loading @@ -198,69 +191,6 @@ public class PanelController implements OnClickListener { imageCrop.invalidate(); } public void nextAspectButton() { if (mAspectButton instanceof ImageButtonTitle && mCurrentImage instanceof ImageCrop) { switch (mCurrentAspectButton) { case ASPECT_NONE: ((ImageButtonTitle) mAspectButton).setText(mContext .getString(R.string.aspect) + " " + mContext.getString(R.string.aspect1to1_effect)); ((ImageCrop) mCurrentImage).apply(1, 1); break; case ASPECT_1TO1: ((ImageButtonTitle) mAspectButton).setText(mContext .getString(R.string.aspect) + " " + mContext.getString(R.string.aspect5to7_effect)); ((ImageCrop) mCurrentImage).apply(7, 5); break; case ASPECT_5TO7: ((ImageButtonTitle) mAspectButton).setText(mContext .getString(R.string.aspect) + " " + mContext.getString(R.string.aspect4to6_effect)); ((ImageCrop) mCurrentImage).apply(6, 4); break; case ASPECT_4TO6: ((ImageButtonTitle) mAspectButton).setText(mContext .getString(R.string.aspect) + " " + mContext.getString(R.string.aspect9to16_effect)); ((ImageCrop) mCurrentImage).apply(16, 9); break; case ASPECT_16TO9: ((ImageButtonTitle) mAspectButton).setText(mContext .getString(R.string.aspect) + " " + mContext.getString(R.string.aspectOriginal_effect)); ((ImageCrop) mCurrentImage).applyOriginal(); break; case ASPECT_ORIG: ((ImageButtonTitle) mAspectButton).setText(mContext .getString(R.string.aspect) + " " + mContext.getString(R.string.aspectNone_effect)); ((ImageCrop) mCurrentImage).applyClear(); break; default: ((ImageButtonTitle) mAspectButton).setText(mContext .getString(R.string.aspect) + " " + mContext.getString(R.string.aspectNone_effect)); ((ImageCrop) mCurrentImage).applyClear(); mCurrentAspectButton = ASPECT_NONE; break; } mCurrentAspectButton = (mCurrentAspectButton + 1) % NUMBER_OF_ASPECT_BUTTONS; } } void setCurrentAspectButton(int n) { mCurrentAspectButton = n; } public void showAspectButtons() { if (mAspectButton != null) mAspectButton.setVisibility(View.VISIBLE); Loading Loading @@ -653,8 +583,10 @@ public class PanelController implements OnClickListener { String ename = mCurrentImage.getContext().getString(R.string.crop); mUtilityPanel.setEffectName(ename); mUtilityPanel.setShowParameter(false); mUtilityPanel.setCurrentAspectButton(-1); mUtilityPanel.nextAspectButton(); if (mCurrentImage instanceof ImageCrop && mUtilityPanel.firstTimeCropDisplayed){ ((ImageCrop) mCurrentImage).applyOriginal(); mUtilityPanel.firstTimeCropDisplayed = false; } mUtilityPanel.showAspectButtons(); break; } Loading Loading @@ -760,7 +692,6 @@ public class PanelController implements OnClickListener { break; } case R.id.aspect: { mUtilityPanel.nextAspectButton(); mUtilityPanel.showAspectButtons(); break; } Loading src/com/android/gallery3d/filtershow/filters/ImageFilterGeometry.java +7 −7 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import com.android.gallery3d.filtershow.imageshow.GeometryMath; import com.android.gallery3d.filtershow.imageshow.GeometryMetadata; public class ImageFilterGeometry extends ImageFilter { Loading Loading @@ -78,19 +79,18 @@ public class ImageFilterGeometry extends ImageFilter { } else { temp = Bitmap.createBitmap(cropBounds.width(), cropBounds.height(), mConfig); } float[] displayCenter = { temp.getWidth() / 2f, temp.getHeight() / 2f }; Matrix m1 = mGeometry.buildTotalXform(bitmap.getWidth(), bitmap.getHeight(), displayCenter); RectF rp = mGeometry.getPhotoBounds(); RectF rc = mGeometry.getPreviewCropBounds(); Matrix drawMatrix = mGeometry.buildTotalXform(rp.width(), rp.height(), rc.width(), rc.height(), rc.left, rc.top, mGeometry.getRotation(), mGeometry.getStraightenRotation(), bitmap.getWidth() / rp.width(), null); Canvas canvas = new Canvas(temp); Paint paint = new Paint(); paint.setAntiAlias(true); paint.setFilterBitmap(true); paint.setDither(true); canvas.drawBitmap(bitmap, drawMatrix, paint); canvas.drawBitmap(bitmap, m1, paint); return temp; } Loading src/com/android/gallery3d/filtershow/imageshow/GeometryMath.java +35 −9 Original line number Diff line number Diff line Loading @@ -16,8 +16,12 @@ package com.android.gallery3d.filtershow.imageshow; import android.graphics.RectF; public class GeometryMath { protected static float clamp(float i, float low, float high) { // Math operations for 2d vectors public static float clamp(float i, float low, float high) { return Math.max(Math.min(i, high), low); } Loading @@ -35,36 +39,58 @@ public class GeometryMath { float[] ret = { (x1 + u * (x2 - x1)), (y1 + u * (y2 - y1)) }; return ret; float [] vec = {ret[0] - point[0], ret[1] - point[1] }; return vec; } // A . B protected static float dotProduct(float[] a, float[] b){ public static float dotProduct(float[] a, float[] b){ return a[0] * b[0] + a[1] * b[1]; } protected static float[] normalize(float[] a){ public static float[] normalize(float[] a){ float length = (float) Math.sqrt(a[0] * a[0] + a[1] * a[1]); float[] b = { a[0] / length, a[1] / length }; return b; } // A onto B protected static float scalarProjection(float[] a, float[] b){ public static float scalarProjection(float[] a, float[] b){ float length = (float) Math.sqrt(b[0] * b[0] + b[1] * b[1]); return dotProduct(a, b) / length; } protected static float[] getVectorFromPoints(float [] point1, float [] point2){ public static float[] getVectorFromPoints(float [] point1, float [] point2){ float [] p = { point2[0] - point1[0], point2[1] - point1[1] }; return p; } protected static float[] getUnitVectorFromPoints(float [] point1, float [] point2){ public static float[] getUnitVectorFromPoints(float [] point1, float [] point2){ float [] p = { point2[0] - point1[0], point2[1] - point1[1] }; float length = (float) Math.sqrt(p[0] * p[0] + p[1] * p[1]); p[0] = p[0] / length; p[1] = p[1] / length; return p; } public static RectF scaleRect(RectF r, float scale){ return new RectF(r.left * scale, r.top * scale, r.right * scale, r.bottom * scale); } // A - B public static float[] vectorSubtract(float [] a, float [] b){ int len = a.length; if (len != b.length) return null; float [] ret = new float[len]; for (int i = 0; i < len; i++){ ret[i] = a[i] - b[i]; } return ret; } public static float vectorLength(float [] a){ return (float) Math.sqrt(a[0] * a[0] + a[1] * a[1]); } } src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java +149 −20 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ import android.graphics.RectF; import com.android.gallery3d.filtershow.filters.ImageFilterGeometry; import java.util.Arrays; public class GeometryMetadata { // Applied in order: rotate, crop, scale. // Do not scale saved image (presumably?). Loading Loading @@ -178,22 +180,34 @@ public class GeometryMetadata { + ",photoRect=" + mPhotoBounds.toShortString() + "]"; } protected Matrix getHorizontalMatrix(float width) { // TODO: refactor away protected static Matrix getHorizontalMatrix(float width) { Matrix flipHorizontalMatrix = new Matrix(); flipHorizontalMatrix.setScale(-1, 1); flipHorizontalMatrix.postTranslate(width, 0); return flipHorizontalMatrix; } protected Matrix getVerticalMatrix(float height) { protected static void concatHorizontalMatrix(Matrix m, float width) { m.postScale(-1, 1); m.postTranslate(width, 0); } // TODO: refactor away protected static 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(); protected static void concatVerticalMatrix(Matrix m, float height) { m.postScale(1, -1); m.postTranslate(0, height); } // TODO: refactor away public static Matrix getFlipMatrix(float width, float height, FLIP type) { if (type == FLIP.HORIZONTAL) { return getHorizontalMatrix(width); } else if (type == FLIP.VERTICAL) { Loading @@ -209,10 +223,28 @@ public class GeometryMetadata { } } public static void concatMirrorMatrix(Matrix m, float width, float height, FLIP type) { if (type == FLIP.HORIZONTAL) { concatHorizontalMatrix(m, width); } else if (type == FLIP.VERTICAL) { concatVerticalMatrix(m, height); } else if (type == FLIP.BOTH) { concatVerticalMatrix(m, height); concatHorizontalMatrix(m, width); } } // TODO: refactor away public Matrix getFlipMatrix(float width, float height) { FLIP type = getFlipType(); return getFlipMatrix(width, height, type); } public boolean hasSwitchedWidthHeight() { return (((int) (mRotation / 90)) % 2) != 0; } // TODO: refactor away public Matrix buildGeometryMatrix(float width, float height, float scaling, float dx, float dy, float rotation) { float dx0 = width / 2; Loading @@ -225,6 +257,7 @@ public class GeometryMetadata { return m; } // TODO: refactor away public Matrix buildGeometryMatrix(float width, float height, float scaling, float dx, float dy, boolean onlyRotate) { float rot = mRotation; Loading @@ -234,28 +267,124 @@ public class GeometryMetadata { return buildGeometryMatrix(width, height, scaling, dx, dy, rot); } // TODO: refactor away public Matrix buildGeometryUIMatrix(float scaling, float dx, float dy) { float w = mPhotoBounds.width(); float h = mPhotoBounds.height(); return buildGeometryMatrix(w, h, scaling, dx, dy, false); } public Matrix buildTotalXform(float pwidth, float pheight, float cwidth, float cheight, float cleft, float ctop, float rotation, float straighten, float scale, RectF dst) { float s_pwidth = pwidth * scale; float s_pheight = pheight * scale; Matrix m = getFlipMatrix(s_pwidth, s_pheight); m.postRotate(rotation + straighten, s_pwidth / 2, s_pheight / 2); Matrix m1 = getFlipMatrix(s_pwidth, s_pheight); m1.postRotate(rotation, s_pwidth / 2, s_pheight / 2); // find new top left for crop. RectF crop = new RectF(cleft * scale, ctop * scale, (cleft + cwidth) * scale, (ctop + cheight) * scale); if (!m1.mapRect(crop)) return null; if (dst != null) dst.set(crop); m.postTranslate(-crop.left, -crop.top); public static Matrix buildPhotoMatrix(RectF photo, RectF crop, float rotation, float straighten, FLIP type) { Matrix m = new Matrix(); m.setRotate(straighten, photo.centerX(), photo.centerY()); concatMirrorMatrix(m, photo.right, photo.bottom, type); m.postRotate(rotation, crop.centerX(), crop.centerY()); return m; } public static Matrix buildCropMatrix(RectF crop, float rotation) { Matrix m = new Matrix(); m.setRotate(rotation, crop.centerX(), crop.centerY()); return m; } public static void concatRecenterMatrix(Matrix m, float[] currentCenter, float[] newCenter) { m.postTranslate(newCenter[0] - currentCenter[0], newCenter[1] - currentCenter[1]); } /** * Builds a matrix to transform a bitmap of width bmWidth and height * bmHeight so that the region of the bitmap being cropped to is * oriented and centered at displayCenter. * * @param bmWidth * @param bmHeight * @param displayCenter * @return */ public Matrix buildTotalXform(float bmWidth, float bmHeight, float[] displayCenter) { RectF rp = getPhotoBounds(); RectF rc = getPreviewCropBounds(); float scale = bmWidth / rp.width(); RectF scaledCrop = GeometryMath.scaleRect(rc, scale); RectF scaledPhoto = GeometryMath.scaleRect(rp, scale); Matrix m1 = GeometryMetadata.buildWanderingCropMatrix(scaledPhoto, scaledCrop, getRotation(), getStraightenRotation(), getFlipType(), displayCenter); float[] cropCenter = { scaledCrop.centerX(), scaledCrop.centerY() }; m1.mapPoints(cropCenter); GeometryMetadata.concatRecenterMatrix(m1, cropCenter, displayCenter); m1.preRotate(getStraightenRotation(), scaledPhoto.centerX(), scaledPhoto.centerY()); return m1; } /** * Builds a matrix that rotates photo rect about it's center by the * straighten angle, mirrors it about the crop center, and rotates it about * the crop center by the rotation angle, and re-centers the photo rect. * * @param photo * @param crop * @param rotation * @param straighten * @param type * @param newCenter * @return */ public static Matrix buildCenteredPhotoMatrix(RectF photo, RectF crop, float rotation, float straighten, FLIP type, float[] newCenter) { Matrix m = buildPhotoMatrix(photo, crop, rotation, straighten, type); float[] center = { photo.centerX(), photo.centerY() }; m.mapPoints(center); concatRecenterMatrix(m, center, newCenter); return m; } /** * Builds a matrix that rotates a crop rect about it's center by rotation * angle, then re-centers the crop rect. * * @param crop * @param rotation * @param newCenter * @return */ public static Matrix buildCenteredCropMatrix(RectF crop, float rotation, float[] newCenter) { Matrix m = buildCropMatrix(crop, rotation); float[] center = { crop.centerX(), crop.centerY() }; m.mapPoints(center); concatRecenterMatrix(m, center, newCenter); return m; } /** * Builds a matrix that transforms the crop rect to its view coordinates * inside the photo rect. * * @param photo * @param crop * @param rotation * @param straighten * @param type * @param newCenter * @return */ public static Matrix buildWanderingCropMatrix(RectF photo, RectF crop, float rotation, float straighten, FLIP type, float[] newCenter) { Matrix m = buildCenteredPhotoMatrix(photo, crop, rotation, straighten, type, newCenter); m.preRotate(-straighten, photo.centerX(), photo.centerY()); return m; } } src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java +25 −9 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ public class ImageCrop extends ImageGeometry { private float mAspectHeight = 1; private boolean mFixAspectRatio = false; private float mLastRot = 0; private final Paint borderPaint; private int movingEdges; Loading Loading @@ -90,6 +91,12 @@ public class ImageCrop extends ImageGeometry { return getContext().getString(R.string.crop); } private void swapAspect(){ float temp = mAspectWidth; mAspectWidth = mAspectHeight; mAspectHeight = temp; } private boolean switchCropBounds(int moving_corner, RectF dst) { RectF crop = getCropBoundsDisplayed(); float dx1 = 0; Loading Loading @@ -144,9 +151,7 @@ public class ImageCrop extends ImageGeometry { Log.v(LOGTAG, "FAILED TO MAP RECTANGLE TO RECTANGLE"); return false; } float temp = mAspectWidth; mAspectWidth = mAspectHeight; mAspectHeight = temp; swapAspect(); dst.set(newCrop); return true; } Loading Loading @@ -565,6 +570,11 @@ public class ImageCrop extends ImageGeometry { @Override protected void gainedVisibility() { float rot = getLocalRotation(); // if has changed orientation via rotate if( ((int) ((rot - mLastRot) / 90)) % 2 != 0 ){ swapAspect(); } cropSetup(); mFirstDraw = true; } Loading @@ -577,19 +587,20 @@ public class ImageCrop extends ImageGeometry { @Override protected void lostVisibility() { mLastRot = getLocalRotation(); } private void drawRuleOfThird(Canvas canvas, RectF bounds) { private void drawRuleOfThird(Canvas canvas, RectF bounds, Paint p) { float stepX = bounds.width() / 3.0f; float stepY = bounds.height() / 3.0f; float x = bounds.left + stepX; float y = bounds.top + stepY; for (int i = 0; i < 2; i++) { canvas.drawLine(x, bounds.top, x, bounds.bottom, gPaint); canvas.drawLine(x, bounds.top, x, bounds.bottom, p); x += stepX; } for (int j = 0; j < 2; j++) { canvas.drawLine(bounds.left, y, bounds.right, y, gPaint); canvas.drawLine(bounds.left, y, bounds.right, y, p); y += stepY; } } Loading @@ -607,17 +618,22 @@ public class ImageCrop extends ImageGeometry { mFirstDraw = false; } float rotation = getLocalRotation(); drawTransformedBitmap(canvas, image, gPaint, true); RectF crop = drawTransformed(canvas, image, gPaint); gPaint.setColor(mBorderColor); gPaint.setStrokeWidth(3); gPaint.setStyle(Paint.Style.STROKE); drawRuleOfThird(canvas, crop, gPaint); gPaint.setColor(mBorderColor); gPaint.setStrokeWidth(3); gPaint.setStyle(Paint.Style.STROKE); drawStraighten(canvas, gPaint); RectF scaledCrop = unrotatedCropBounds(); drawRuleOfThird(canvas, scaledCrop); int decoded_moving = decoder(movingEdges, rotation); canvas.save(); canvas.rotate(rotation, mCenterX, mCenterY); RectF scaledCrop = unrotatedCropBounds(); boolean notMoving = decoded_moving == 0; if (((decoded_moving & MOVE_TOP) != 0) || notMoving) { drawIndicator(canvas, cropIndicator, scaledCrop.centerX(), scaledCrop.top); Loading Loading
src/com/android/gallery3d/filtershow/PanelController.java +5 −74 Original line number Diff line number Diff line Loading @@ -139,14 +139,7 @@ public class PanelController implements OnClickListener { private boolean mShowParameterValue = false; private View mAspectButton = null; private View mCurvesButton = null; private int mCurrentAspectButton = 0; private static final int NUMBER_OF_ASPECT_BUTTONS = 6; private static final int ASPECT_NONE = 0; private static final int ASPECT_1TO1 = 1; private static final int ASPECT_5TO7 = 2; private static final int ASPECT_4TO6 = 3; private static final int ASPECT_16TO9 = 4; private static final int ASPECT_ORIG = 5; boolean firstTimeCropDisplayed = true; public UtilityPanel(Context context, View view, View textView, View aspectButton, View curvesButton) { Loading Loading @@ -198,69 +191,6 @@ public class PanelController implements OnClickListener { imageCrop.invalidate(); } public void nextAspectButton() { if (mAspectButton instanceof ImageButtonTitle && mCurrentImage instanceof ImageCrop) { switch (mCurrentAspectButton) { case ASPECT_NONE: ((ImageButtonTitle) mAspectButton).setText(mContext .getString(R.string.aspect) + " " + mContext.getString(R.string.aspect1to1_effect)); ((ImageCrop) mCurrentImage).apply(1, 1); break; case ASPECT_1TO1: ((ImageButtonTitle) mAspectButton).setText(mContext .getString(R.string.aspect) + " " + mContext.getString(R.string.aspect5to7_effect)); ((ImageCrop) mCurrentImage).apply(7, 5); break; case ASPECT_5TO7: ((ImageButtonTitle) mAspectButton).setText(mContext .getString(R.string.aspect) + " " + mContext.getString(R.string.aspect4to6_effect)); ((ImageCrop) mCurrentImage).apply(6, 4); break; case ASPECT_4TO6: ((ImageButtonTitle) mAspectButton).setText(mContext .getString(R.string.aspect) + " " + mContext.getString(R.string.aspect9to16_effect)); ((ImageCrop) mCurrentImage).apply(16, 9); break; case ASPECT_16TO9: ((ImageButtonTitle) mAspectButton).setText(mContext .getString(R.string.aspect) + " " + mContext.getString(R.string.aspectOriginal_effect)); ((ImageCrop) mCurrentImage).applyOriginal(); break; case ASPECT_ORIG: ((ImageButtonTitle) mAspectButton).setText(mContext .getString(R.string.aspect) + " " + mContext.getString(R.string.aspectNone_effect)); ((ImageCrop) mCurrentImage).applyClear(); break; default: ((ImageButtonTitle) mAspectButton).setText(mContext .getString(R.string.aspect) + " " + mContext.getString(R.string.aspectNone_effect)); ((ImageCrop) mCurrentImage).applyClear(); mCurrentAspectButton = ASPECT_NONE; break; } mCurrentAspectButton = (mCurrentAspectButton + 1) % NUMBER_OF_ASPECT_BUTTONS; } } void setCurrentAspectButton(int n) { mCurrentAspectButton = n; } public void showAspectButtons() { if (mAspectButton != null) mAspectButton.setVisibility(View.VISIBLE); Loading Loading @@ -653,8 +583,10 @@ public class PanelController implements OnClickListener { String ename = mCurrentImage.getContext().getString(R.string.crop); mUtilityPanel.setEffectName(ename); mUtilityPanel.setShowParameter(false); mUtilityPanel.setCurrentAspectButton(-1); mUtilityPanel.nextAspectButton(); if (mCurrentImage instanceof ImageCrop && mUtilityPanel.firstTimeCropDisplayed){ ((ImageCrop) mCurrentImage).applyOriginal(); mUtilityPanel.firstTimeCropDisplayed = false; } mUtilityPanel.showAspectButtons(); break; } Loading Loading @@ -760,7 +692,6 @@ public class PanelController implements OnClickListener { break; } case R.id.aspect: { mUtilityPanel.nextAspectButton(); mUtilityPanel.showAspectButtons(); break; } Loading
src/com/android/gallery3d/filtershow/filters/ImageFilterGeometry.java +7 −7 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import com.android.gallery3d.filtershow.imageshow.GeometryMath; import com.android.gallery3d.filtershow.imageshow.GeometryMetadata; public class ImageFilterGeometry extends ImageFilter { Loading Loading @@ -78,19 +79,18 @@ public class ImageFilterGeometry extends ImageFilter { } else { temp = Bitmap.createBitmap(cropBounds.width(), cropBounds.height(), mConfig); } float[] displayCenter = { temp.getWidth() / 2f, temp.getHeight() / 2f }; Matrix m1 = mGeometry.buildTotalXform(bitmap.getWidth(), bitmap.getHeight(), displayCenter); RectF rp = mGeometry.getPhotoBounds(); RectF rc = mGeometry.getPreviewCropBounds(); Matrix drawMatrix = mGeometry.buildTotalXform(rp.width(), rp.height(), rc.width(), rc.height(), rc.left, rc.top, mGeometry.getRotation(), mGeometry.getStraightenRotation(), bitmap.getWidth() / rp.width(), null); Canvas canvas = new Canvas(temp); Paint paint = new Paint(); paint.setAntiAlias(true); paint.setFilterBitmap(true); paint.setDither(true); canvas.drawBitmap(bitmap, drawMatrix, paint); canvas.drawBitmap(bitmap, m1, paint); return temp; } Loading
src/com/android/gallery3d/filtershow/imageshow/GeometryMath.java +35 −9 Original line number Diff line number Diff line Loading @@ -16,8 +16,12 @@ package com.android.gallery3d.filtershow.imageshow; import android.graphics.RectF; public class GeometryMath { protected static float clamp(float i, float low, float high) { // Math operations for 2d vectors public static float clamp(float i, float low, float high) { return Math.max(Math.min(i, high), low); } Loading @@ -35,36 +39,58 @@ public class GeometryMath { float[] ret = { (x1 + u * (x2 - x1)), (y1 + u * (y2 - y1)) }; return ret; float [] vec = {ret[0] - point[0], ret[1] - point[1] }; return vec; } // A . B protected static float dotProduct(float[] a, float[] b){ public static float dotProduct(float[] a, float[] b){ return a[0] * b[0] + a[1] * b[1]; } protected static float[] normalize(float[] a){ public static float[] normalize(float[] a){ float length = (float) Math.sqrt(a[0] * a[0] + a[1] * a[1]); float[] b = { a[0] / length, a[1] / length }; return b; } // A onto B protected static float scalarProjection(float[] a, float[] b){ public static float scalarProjection(float[] a, float[] b){ float length = (float) Math.sqrt(b[0] * b[0] + b[1] * b[1]); return dotProduct(a, b) / length; } protected static float[] getVectorFromPoints(float [] point1, float [] point2){ public static float[] getVectorFromPoints(float [] point1, float [] point2){ float [] p = { point2[0] - point1[0], point2[1] - point1[1] }; return p; } protected static float[] getUnitVectorFromPoints(float [] point1, float [] point2){ public static float[] getUnitVectorFromPoints(float [] point1, float [] point2){ float [] p = { point2[0] - point1[0], point2[1] - point1[1] }; float length = (float) Math.sqrt(p[0] * p[0] + p[1] * p[1]); p[0] = p[0] / length; p[1] = p[1] / length; return p; } public static RectF scaleRect(RectF r, float scale){ return new RectF(r.left * scale, r.top * scale, r.right * scale, r.bottom * scale); } // A - B public static float[] vectorSubtract(float [] a, float [] b){ int len = a.length; if (len != b.length) return null; float [] ret = new float[len]; for (int i = 0; i < len; i++){ ret[i] = a[i] - b[i]; } return ret; } public static float vectorLength(float [] a){ return (float) Math.sqrt(a[0] * a[0] + a[1] * a[1]); } }
src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java +149 −20 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ import android.graphics.RectF; import com.android.gallery3d.filtershow.filters.ImageFilterGeometry; import java.util.Arrays; public class GeometryMetadata { // Applied in order: rotate, crop, scale. // Do not scale saved image (presumably?). Loading Loading @@ -178,22 +180,34 @@ public class GeometryMetadata { + ",photoRect=" + mPhotoBounds.toShortString() + "]"; } protected Matrix getHorizontalMatrix(float width) { // TODO: refactor away protected static Matrix getHorizontalMatrix(float width) { Matrix flipHorizontalMatrix = new Matrix(); flipHorizontalMatrix.setScale(-1, 1); flipHorizontalMatrix.postTranslate(width, 0); return flipHorizontalMatrix; } protected Matrix getVerticalMatrix(float height) { protected static void concatHorizontalMatrix(Matrix m, float width) { m.postScale(-1, 1); m.postTranslate(width, 0); } // TODO: refactor away protected static 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(); protected static void concatVerticalMatrix(Matrix m, float height) { m.postScale(1, -1); m.postTranslate(0, height); } // TODO: refactor away public static Matrix getFlipMatrix(float width, float height, FLIP type) { if (type == FLIP.HORIZONTAL) { return getHorizontalMatrix(width); } else if (type == FLIP.VERTICAL) { Loading @@ -209,10 +223,28 @@ public class GeometryMetadata { } } public static void concatMirrorMatrix(Matrix m, float width, float height, FLIP type) { if (type == FLIP.HORIZONTAL) { concatHorizontalMatrix(m, width); } else if (type == FLIP.VERTICAL) { concatVerticalMatrix(m, height); } else if (type == FLIP.BOTH) { concatVerticalMatrix(m, height); concatHorizontalMatrix(m, width); } } // TODO: refactor away public Matrix getFlipMatrix(float width, float height) { FLIP type = getFlipType(); return getFlipMatrix(width, height, type); } public boolean hasSwitchedWidthHeight() { return (((int) (mRotation / 90)) % 2) != 0; } // TODO: refactor away public Matrix buildGeometryMatrix(float width, float height, float scaling, float dx, float dy, float rotation) { float dx0 = width / 2; Loading @@ -225,6 +257,7 @@ public class GeometryMetadata { return m; } // TODO: refactor away public Matrix buildGeometryMatrix(float width, float height, float scaling, float dx, float dy, boolean onlyRotate) { float rot = mRotation; Loading @@ -234,28 +267,124 @@ public class GeometryMetadata { return buildGeometryMatrix(width, height, scaling, dx, dy, rot); } // TODO: refactor away public Matrix buildGeometryUIMatrix(float scaling, float dx, float dy) { float w = mPhotoBounds.width(); float h = mPhotoBounds.height(); return buildGeometryMatrix(w, h, scaling, dx, dy, false); } public Matrix buildTotalXform(float pwidth, float pheight, float cwidth, float cheight, float cleft, float ctop, float rotation, float straighten, float scale, RectF dst) { float s_pwidth = pwidth * scale; float s_pheight = pheight * scale; Matrix m = getFlipMatrix(s_pwidth, s_pheight); m.postRotate(rotation + straighten, s_pwidth / 2, s_pheight / 2); Matrix m1 = getFlipMatrix(s_pwidth, s_pheight); m1.postRotate(rotation, s_pwidth / 2, s_pheight / 2); // find new top left for crop. RectF crop = new RectF(cleft * scale, ctop * scale, (cleft + cwidth) * scale, (ctop + cheight) * scale); if (!m1.mapRect(crop)) return null; if (dst != null) dst.set(crop); m.postTranslate(-crop.left, -crop.top); public static Matrix buildPhotoMatrix(RectF photo, RectF crop, float rotation, float straighten, FLIP type) { Matrix m = new Matrix(); m.setRotate(straighten, photo.centerX(), photo.centerY()); concatMirrorMatrix(m, photo.right, photo.bottom, type); m.postRotate(rotation, crop.centerX(), crop.centerY()); return m; } public static Matrix buildCropMatrix(RectF crop, float rotation) { Matrix m = new Matrix(); m.setRotate(rotation, crop.centerX(), crop.centerY()); return m; } public static void concatRecenterMatrix(Matrix m, float[] currentCenter, float[] newCenter) { m.postTranslate(newCenter[0] - currentCenter[0], newCenter[1] - currentCenter[1]); } /** * Builds a matrix to transform a bitmap of width bmWidth and height * bmHeight so that the region of the bitmap being cropped to is * oriented and centered at displayCenter. * * @param bmWidth * @param bmHeight * @param displayCenter * @return */ public Matrix buildTotalXform(float bmWidth, float bmHeight, float[] displayCenter) { RectF rp = getPhotoBounds(); RectF rc = getPreviewCropBounds(); float scale = bmWidth / rp.width(); RectF scaledCrop = GeometryMath.scaleRect(rc, scale); RectF scaledPhoto = GeometryMath.scaleRect(rp, scale); Matrix m1 = GeometryMetadata.buildWanderingCropMatrix(scaledPhoto, scaledCrop, getRotation(), getStraightenRotation(), getFlipType(), displayCenter); float[] cropCenter = { scaledCrop.centerX(), scaledCrop.centerY() }; m1.mapPoints(cropCenter); GeometryMetadata.concatRecenterMatrix(m1, cropCenter, displayCenter); m1.preRotate(getStraightenRotation(), scaledPhoto.centerX(), scaledPhoto.centerY()); return m1; } /** * Builds a matrix that rotates photo rect about it's center by the * straighten angle, mirrors it about the crop center, and rotates it about * the crop center by the rotation angle, and re-centers the photo rect. * * @param photo * @param crop * @param rotation * @param straighten * @param type * @param newCenter * @return */ public static Matrix buildCenteredPhotoMatrix(RectF photo, RectF crop, float rotation, float straighten, FLIP type, float[] newCenter) { Matrix m = buildPhotoMatrix(photo, crop, rotation, straighten, type); float[] center = { photo.centerX(), photo.centerY() }; m.mapPoints(center); concatRecenterMatrix(m, center, newCenter); return m; } /** * Builds a matrix that rotates a crop rect about it's center by rotation * angle, then re-centers the crop rect. * * @param crop * @param rotation * @param newCenter * @return */ public static Matrix buildCenteredCropMatrix(RectF crop, float rotation, float[] newCenter) { Matrix m = buildCropMatrix(crop, rotation); float[] center = { crop.centerX(), crop.centerY() }; m.mapPoints(center); concatRecenterMatrix(m, center, newCenter); return m; } /** * Builds a matrix that transforms the crop rect to its view coordinates * inside the photo rect. * * @param photo * @param crop * @param rotation * @param straighten * @param type * @param newCenter * @return */ public static Matrix buildWanderingCropMatrix(RectF photo, RectF crop, float rotation, float straighten, FLIP type, float[] newCenter) { Matrix m = buildCenteredPhotoMatrix(photo, crop, rotation, straighten, type, newCenter); m.preRotate(-straighten, photo.centerX(), photo.centerY()); return m; } }
src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java +25 −9 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ public class ImageCrop extends ImageGeometry { private float mAspectHeight = 1; private boolean mFixAspectRatio = false; private float mLastRot = 0; private final Paint borderPaint; private int movingEdges; Loading Loading @@ -90,6 +91,12 @@ public class ImageCrop extends ImageGeometry { return getContext().getString(R.string.crop); } private void swapAspect(){ float temp = mAspectWidth; mAspectWidth = mAspectHeight; mAspectHeight = temp; } private boolean switchCropBounds(int moving_corner, RectF dst) { RectF crop = getCropBoundsDisplayed(); float dx1 = 0; Loading Loading @@ -144,9 +151,7 @@ public class ImageCrop extends ImageGeometry { Log.v(LOGTAG, "FAILED TO MAP RECTANGLE TO RECTANGLE"); return false; } float temp = mAspectWidth; mAspectWidth = mAspectHeight; mAspectHeight = temp; swapAspect(); dst.set(newCrop); return true; } Loading Loading @@ -565,6 +570,11 @@ public class ImageCrop extends ImageGeometry { @Override protected void gainedVisibility() { float rot = getLocalRotation(); // if has changed orientation via rotate if( ((int) ((rot - mLastRot) / 90)) % 2 != 0 ){ swapAspect(); } cropSetup(); mFirstDraw = true; } Loading @@ -577,19 +587,20 @@ public class ImageCrop extends ImageGeometry { @Override protected void lostVisibility() { mLastRot = getLocalRotation(); } private void drawRuleOfThird(Canvas canvas, RectF bounds) { private void drawRuleOfThird(Canvas canvas, RectF bounds, Paint p) { float stepX = bounds.width() / 3.0f; float stepY = bounds.height() / 3.0f; float x = bounds.left + stepX; float y = bounds.top + stepY; for (int i = 0; i < 2; i++) { canvas.drawLine(x, bounds.top, x, bounds.bottom, gPaint); canvas.drawLine(x, bounds.top, x, bounds.bottom, p); x += stepX; } for (int j = 0; j < 2; j++) { canvas.drawLine(bounds.left, y, bounds.right, y, gPaint); canvas.drawLine(bounds.left, y, bounds.right, y, p); y += stepY; } } Loading @@ -607,17 +618,22 @@ public class ImageCrop extends ImageGeometry { mFirstDraw = false; } float rotation = getLocalRotation(); drawTransformedBitmap(canvas, image, gPaint, true); RectF crop = drawTransformed(canvas, image, gPaint); gPaint.setColor(mBorderColor); gPaint.setStrokeWidth(3); gPaint.setStyle(Paint.Style.STROKE); drawRuleOfThird(canvas, crop, gPaint); gPaint.setColor(mBorderColor); gPaint.setStrokeWidth(3); gPaint.setStyle(Paint.Style.STROKE); drawStraighten(canvas, gPaint); RectF scaledCrop = unrotatedCropBounds(); drawRuleOfThird(canvas, scaledCrop); int decoded_moving = decoder(movingEdges, rotation); canvas.save(); canvas.rotate(rotation, mCenterX, mCenterY); RectF scaledCrop = unrotatedCropBounds(); boolean notMoving = decoded_moving == 0; if (((decoded_moving & MOVE_TOP) != 0) || notMoving) { drawIndicator(canvas, cropIndicator, scaledCrop.centerX(), scaledCrop.top); Loading