diff options
Diffstat (limited to 'src/com/android/gallery3d/filtershow/imageshow')
3 files changed, 518 insertions, 0 deletions
diff --git a/src/com/android/gallery3d/filtershow/imageshow/GradControl.java b/src/com/android/gallery3d/filtershow/imageshow/GradControl.java new file mode 100644 index 000000000..964da99e9 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/imageshow/GradControl.java @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.gallery3d.filtershow.imageshow; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.DashPathEffect; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.RadialGradient; +import android.graphics.Rect; +import android.graphics.Shader; + +import com.android.gallery3d.R; + +public class GradControl { + private float mPoint1X = Float.NaN; // used to flag parameters have not been set + private float mPoint1Y = 0; + private float mPoint2X = 200; + private float mPoint2Y = 300; + private int mMinTouchDist = 80;// should be a resource & in dips + + private float[] handlex = new float[3]; + private float[] handley = new float[3]; + private int mSliderColor; + private int mCenterDotSize; + private float mDownX; + private float mDownY; + private float mDownPoint1X; + private float mDownPoint1Y; + private float mDownPoint2X; + private float mDownPoint2Y; + Rect mImageBounds; + int mImageHeight; + private Matrix mScrToImg; + Paint mPaint = new Paint(); + DashPathEffect mDash = new DashPathEffect(new float[]{30, 30}, 0); + private boolean mShowReshapeHandles = true; + public final static int HAN_CENTER = 0; + public final static int HAN_NORTH = 2; + public final static int HAN_SOUTH = 1; + private int[] mPointColorPatern; + private int[] mGrayPointColorPatern; + private float[] mPointRadialPos = new float[]{0, .3f, .31f, 1}; + private int mLineColor; + private int mlineShadowColor; + + public GradControl(Context context) { + + Resources res = context.getResources(); + mCenterDotSize = (int) res.getDimension(R.dimen.gradcontrol_dot_size); + mMinTouchDist = (int) res.getDimension(R.dimen.gradcontrol_min_touch_dist); + int grayPointCenterColor = res.getColor(R.color.gradcontrol_graypoint_center); + int grayPointEdgeColor = res.getColor(R.color.gradcontrol_graypoint_edge); + int pointCenterColor = res.getColor(R.color.gradcontrol_point_center); + int pointEdgeColor = res.getColor(R.color.gradcontrol_point_edge); + int pointShadowStartColor = res.getColor(R.color.gradcontrol_point_shadow_start); + int pointShadowEndColor = res.getColor(R.color.gradcontrol_point_shadow_end); + mPointColorPatern = new int[]{ + pointCenterColor, pointEdgeColor, pointShadowStartColor, pointShadowEndColor}; + mGrayPointColorPatern = new int[]{ + grayPointCenterColor, grayPointEdgeColor, pointShadowStartColor, pointShadowEndColor}; + mSliderColor = Color.WHITE; + mLineColor = res.getColor(R.color.gradcontrol_line_color); + mlineShadowColor = res.getColor(R.color.gradcontrol_line_shadow); + } + + public void setPoint2(float x, float y) { + mPoint2X = x; + mPoint2Y = y; + } + + public void setPoint1(float x, float y) { + mPoint1X = x; + mPoint1Y = y; + } + + public int getCloseHandle(float x, float y) { + float min = Float.MAX_VALUE; + int handle = -1; + for (int i = 0; i < handlex.length; i++) { + float dx = handlex[i] - x; + float dy = handley[i] - y; + float dist = dx * dx + dy * dy; + if (dist < min) { + min = dist; + handle = i; + } + } + + if (min < mMinTouchDist * mMinTouchDist) { + return handle; + } + for (int i = 0; i < handlex.length; i++) { + float dx = handlex[i] - x; + float dy = handley[i] - y; + float dist = (float) Math.sqrt(dx * dx + dy * dy); + } + + return -1; + } + + public void setScrImageInfo(Matrix scrToImg, Rect imageBounds) { + mScrToImg = scrToImg; + mImageBounds = new Rect(imageBounds); + } + + private boolean centerIsOutside(float x1, float y1, float x2, float y2) { + return (!mImageBounds.contains((int) ((x1 + x2) / 2), (int) ((y1 + y2) / 2))); + } + + public void actionDown(float x, float y, Line line) { + float[] point = new float[]{ + x, y}; + mScrToImg.mapPoints(point); + mDownX = point[0]; + mDownY = point[1]; + mDownPoint1X = line.getPoint1X(); + mDownPoint1Y = line.getPoint1Y(); + mDownPoint2X = line.getPoint2X(); + mDownPoint2Y = line.getPoint2Y(); + } + + public void actionMove(int handle, float x, float y, Line line) { + float[] point = new float[]{ + x, y}; + mScrToImg.mapPoints(point); + x = point[0]; + y = point[1]; + + // Test if the matrix is swapping x and y + point[0] = 0; + point[1] = 1; + mScrToImg.mapVectors(point); + boolean swapxy = (point[0] > 0.0f); + + int sign = 1; + + float dx = x - mDownX; + float dy = y - mDownY; + switch (handle) { + case HAN_CENTER: + if (centerIsOutside(mDownPoint1X + dx, mDownPoint1Y + dy, + mDownPoint2X + dx, mDownPoint2Y + dy)) { + break; + } + line.setPoint1(mDownPoint1X + dx, mDownPoint1Y + dy); + line.setPoint2(mDownPoint2X + dx, mDownPoint2Y + dy); + break; + case HAN_SOUTH: + if (centerIsOutside(mDownPoint1X + dx, mDownPoint1Y + dy, + mDownPoint2X, mDownPoint2Y)) { + break; + } + line.setPoint1(mDownPoint1X + dx, mDownPoint1Y + dy); + break; + case HAN_NORTH: + if (centerIsOutside(mDownPoint1X, mDownPoint1Y, + mDownPoint2X + dx, mDownPoint2Y + dy)) { + break; + } + line.setPoint2(mDownPoint2X + dx, mDownPoint2Y + dy); + break; + } + } + + public void paintGrayPoint(Canvas canvas, float x, float y) { + if (isUndefined()) { + return; + } + + Paint paint = new Paint(); + paint.setStyle(Paint.Style.FILL); + RadialGradient g = new RadialGradient(x, y, mCenterDotSize, mGrayPointColorPatern, + mPointRadialPos, Shader.TileMode.CLAMP); + paint.setShader(g); + canvas.drawCircle(x, y, mCenterDotSize, paint); + } + + public void paintPoint(Canvas canvas, float x, float y) { + if (isUndefined()) { + return; + } + + Paint paint = new Paint(); + paint.setStyle(Paint.Style.FILL); + RadialGradient g = new RadialGradient(x, y, mCenterDotSize, mPointColorPatern, + mPointRadialPos, Shader.TileMode.CLAMP); + paint.setShader(g); + canvas.drawCircle(x, y, mCenterDotSize, paint); + } + + void paintLines(Canvas canvas, float p1x, float p1y, float p2x, float p2y) { + if (isUndefined()) { + return; + } + + mPaint.setAntiAlias(true); + mPaint.setStyle(Paint.Style.STROKE); + + mPaint.setStrokeWidth(6); + mPaint.setColor(mlineShadowColor); + mPaint.setPathEffect(mDash); + paintOvallines(canvas, mPaint, p1x, p1y, p2x, p2y); + + mPaint.setStrokeWidth(3); + mPaint.setColor(mLineColor); + mPaint.setPathEffect(mDash); + paintOvallines(canvas, mPaint, p1x, p1y, p2x, p2y); + } + + public void paintOvallines( + Canvas canvas, Paint paint, float p1x, float p1y, float p2x, float p2y) { + + + + canvas.drawLine(p1x, p1y, p2x, p2y, paint); + + float cx = (p1x + p2x) / 2; + float cy = (p1y + p2y) / 2; + float dx = p1x - p2x; + float dy = p1y - p2y; + float len = (float) Math.sqrt(dx * dx + dy * dy); + dx *= 2048 / len; + dy *= 2048 / len; + + canvas.drawLine(p1x + dy, p1y - dx, p1x - dy, p1y + dx, paint); + canvas.drawLine(p2x + dy, p2y - dx, p2x - dy, p2y + dx, paint); + } + + public void fillHandles(Canvas canvas, float p1x, float p1y, float p2x, float p2y) { + float cx = (p1x + p2x) / 2; + float cy = (p1y + p2y) / 2; + handlex[0] = cx; + handley[0] = cy; + handlex[1] = p1x; + handley[1] = p1y; + handlex[2] = p2x; + handley[2] = p2y; + + } + + public void draw(Canvas canvas) { + paintLines(canvas, mPoint1X, mPoint1Y, mPoint2X, mPoint2Y); + fillHandles(canvas, mPoint1X, mPoint1Y, mPoint2X, mPoint2Y); + paintPoint(canvas, mPoint2X, mPoint2Y); + paintPoint(canvas, mPoint1X, mPoint1Y); + paintPoint(canvas, (mPoint1X + mPoint2X) / 2, (mPoint1Y + mPoint2Y) / 2); + } + + public boolean isUndefined() { + return Float.isNaN(mPoint1X); + } + + public void setShowReshapeHandles(boolean showReshapeHandles) { + this.mShowReshapeHandles = showReshapeHandles; + } +} diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageGrad.java b/src/com/android/gallery3d/filtershow/imageshow/ImageGrad.java new file mode 100644 index 000000000..ef72e8a6e --- /dev/null +++ b/src/com/android/gallery3d/filtershow/imageshow/ImageGrad.java @@ -0,0 +1,218 @@ +package com.android.gallery3d.filtershow.imageshow; +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.util.AttributeSet; +import android.view.MotionEvent; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.editors.EditorGrad; +import com.android.gallery3d.filtershow.filters.FilterGradRepresentation; + +public class ImageGrad extends ImageShow { + private static final String LOGTAG = "ImageGrad"; + private FilterGradRepresentation mGradRep; + private EditorGrad mEditorGrad; + private int mMinTouchDist; + private int mActiveHandle = -1; + private GradControl mEllipse; + + Matrix mToScr = new Matrix(); + float[] mPointsX = new float[FilterGradRepresentation.MAX_POINTS]; + float[] mPointsY = new float[FilterGradRepresentation.MAX_POINTS]; + + public ImageGrad(Context context) { + super(context); + Resources res = context.getResources(); + mMinTouchDist = res.getDimensionPixelSize(R.dimen.gradcontrol_min_touch_dist); + mEllipse = new GradControl(context); + mEllipse.setShowReshapeHandles(false); + } + + public ImageGrad(Context context, AttributeSet attrs) { + super(context, attrs); + mEllipse = new GradControl(context); + mEllipse.setShowReshapeHandles(false); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + int mask = event.getActionMasked(); + + if (mask == MotionEvent.ACTION_DOWN || mask == MotionEvent.ACTION_UP) { + mGradRep.setInking(MotionEvent.ACTION_DOWN == mask); + } + + if (mActiveHandle == -1) { + if (MotionEvent.ACTION_DOWN != mask) { + return super.onTouchEvent(event); + } + if (event.getPointerCount() == 1) { + mActiveHandle = mEllipse.getCloseHandle(event.getX(), event.getY()); + if (mActiveHandle == -1) { + float x = event.getX(); + float y = event.getY(); + float min_d = Float.MAX_VALUE; + int pos = -1; + for (int i = 0; i < mPointsX.length; i++) { + if (mPointsX[i] == -1) { + continue; + } + float d = (float) Math.hypot(x - mPointsX[i], y - mPointsY[i]); + if ( min_d > d) { + min_d = d; + pos = i; + } + } + if (min_d > mMinTouchDist){ + pos = -1; + } + + if (pos != -1) { + mGradRep.setSelectedPoint(pos); + mGradRep.setInking(true); + resetImageCaches(this); + mEditorGrad.updateSeekBar(mGradRep); + mEditorGrad.commitLocalRepresentation(); + invalidate(); + } + } + } + if (mActiveHandle == -1) { + return super.onTouchEvent(event); + } + } else { + switch (mask) { + case MotionEvent.ACTION_UP: { + + mActiveHandle = -1; + break; + } + case MotionEvent.ACTION_DOWN: { + break; + } + } + } + float x = event.getX(); + float y = event.getY(); + + mEllipse.setScrImageInfo(getScreenToImageMatrix(true), + MasterImage.getImage().getOriginalBounds()); + + switch (mask) { + case (MotionEvent.ACTION_DOWN): { + mEllipse.actionDown(x, y, mGradRep); + break; + } + case (MotionEvent.ACTION_UP): + case (MotionEvent.ACTION_MOVE): { + mEllipse.actionMove(mActiveHandle, x, y, mGradRep); + setRepresentation(mGradRep); + break; + } + } + invalidate(); + mEditorGrad.commitLocalRepresentation(); + return true; + } + + public void setRepresentation(FilterGradRepresentation pointRep) { + mGradRep = pointRep; + Matrix toImg = getScreenToImageMatrix(false); + + toImg.invert(mToScr); + + float[] c1 = new float[] { mGradRep.getPoint1X(), mGradRep.getPoint1Y() }; + float[] c2 = new float[] { mGradRep.getPoint2X(), mGradRep.getPoint2Y() }; + + if (c1[0] == -1) { + float cx = MasterImage.getImage().getOriginalBounds().width() / 2; + float cy = MasterImage.getImage().getOriginalBounds().height() / 2; + float rx = Math.min(cx, cy) * .4f; + + mGradRep.setPoint1(cx, cy-rx); + mGradRep.setPoint2(cx, cy+rx); + c1[0] = cx; + c1[1] = cy-rx; + mToScr.mapPoints(c1); + if (getWidth() != 0) { + mEllipse.setPoint1(c1[0], c1[1]); + c2[0] = cx; + c2[1] = cy+rx; + mToScr.mapPoints(c2); + mEllipse.setPoint2(c2[0], c2[1]); + } + mEditorGrad.commitLocalRepresentation(); + } else { + mToScr.mapPoints(c1); + mToScr.mapPoints(c2); + mEllipse.setPoint1(c1[0], c1[1]); + mEllipse.setPoint2(c2[0], c2[1]); + } + } + + public void drawOtherPoints(Canvas canvas) { + computCenterLocations(); + for (int i = 0; i < mPointsX.length; i++) { + if (mPointsX[i] != -1) { + mEllipse.paintGrayPoint(canvas, mPointsX[i], mPointsY[i]); + } + } + } + + public void computCenterLocations() { + int x1[] = mGradRep.getXPos1(); + int y1[] = mGradRep.getYPos1(); + int x2[] = mGradRep.getXPos2(); + int y2[] = mGradRep.getYPos2(); + int selected = mGradRep.getSelectedPoint(); + boolean m[] = mGradRep.getMask(); + float[] c = new float[2]; + for (int i = 0; i < m.length; i++) { + if (selected == i || !m[i]) { + mPointsX[i] = -1; + continue; + } + + c[0] = (x1[i]+x2[i])/2; + c[1] = (y1[i]+y2[i])/2; + mToScr.mapPoints(c); + + mPointsX[i] = c[0]; + mPointsY[i] = c[1]; + } + } + + public void setEditor(EditorGrad editorGrad) { + mEditorGrad = editorGrad; + } + + @Override + public void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (mGradRep == null) { + return; + } + setRepresentation(mGradRep); + mEllipse.draw(canvas); + drawOtherPoints(canvas); + } + +} diff --git a/src/com/android/gallery3d/filtershow/imageshow/Line.java b/src/com/android/gallery3d/filtershow/imageshow/Line.java new file mode 100644 index 000000000..a767bd809 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/imageshow/Line.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.gallery3d.filtershow.imageshow; + +public interface Line { + void setPoint1(float x, float y); + void setPoint2(float x, float y); + float getPoint1X(); + float getPoint1Y(); + float getPoint2X(); + float getPoint2Y(); +} |