自定义Android图像裁剪
我只想分享我写的这段代码。我尝试搜索一个自定义裁剪活动,但大多数都会导致默认的“com.android.camera.action.crop”,尽管有自定义裁剪或徒手裁剪活动的问题。不管怎样,我只是为自己做了一个,希望它能帮助你们自定义Android图像裁剪,android,crop,Android,Crop,我只想分享我写的这段代码。我尝试搜索一个自定义裁剪活动,但大多数都会导致默认的“com.android.camera.action.crop”,尽管有自定义裁剪或徒手裁剪活动的问题。不管怎样,我只是为自己做了一个,希望它能帮助你们 public class CropView extends ImageView { Paint paint = new Paint(); private int initial_size = 300; private static Point
public class CropView extends ImageView {
Paint paint = new Paint();
private int initial_size = 300;
private static Point leftTop, rightBottom, center, previous;
private static final int DRAG= 0;
private static final int LEFT= 1;
private static final int TOP= 2;
private static final int RIGHT= 3;
private static final int BOTTOM= 4;
private int imageScaledWidth,imageScaledHeight;
// Adding parent class constructors
public CropView(Context context) {
super(context);
initCropView();
}
public CropView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
initCropView();
}
public CropView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initCropView();
}
@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
if(leftTop.equals(0, 0))
resetPoints();
canvas.drawRect(leftTop.x, leftTop.y, rightBottom.x, rightBottom.y, paint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int eventaction = event.getAction();
switch (eventaction) {
case MotionEvent.ACTION_DOWN:
previous.set((int)event.getX(), (int)event.getY());
break;
case MotionEvent.ACTION_MOVE:
if(isActionInsideRectangle(event.getX(), event.getY())) {
adjustRectangle((int)event.getX(), (int)event.getY());
invalidate(); // redraw rectangle
previous.set((int)event.getX(), (int)event.getY());
}
break;
case MotionEvent.ACTION_UP:
previous = new Point();
break;
}
return true;
}
private void initCropView() {
paint.setColor(Color.YELLOW);
paint.setStyle(Style.STROKE);
paint.setStrokeWidth(5);
leftTop = new Point();
rightBottom = new Point();
center = new Point();
previous = new Point();
}
public void resetPoints() {
center.set(getWidth()/2, getHeight()/2);
leftTop.set((getWidth()-initial_size)/2,(getHeight()-initial_size)/2);
rightBottom.set(leftTop.x+initial_size, leftTop.y+initial_size);
}
private static boolean isActionInsideRectangle(float x, float y) {
int buffer = 10;
return (x>=(leftTop.x-buffer)&&x<=(rightBottom.x+buffer)&& y>=(leftTop.y-buffer)&&y<=(rightBottom.y+buffer))?true:false;
}
private boolean isInImageRange(PointF point) {
// Get image matrix values and place them in an array
float[] f = new float[9];
getImageMatrix().getValues(f);
// Calculate the scaled dimensions
imageScaledWidth = Math.round(getDrawable().getIntrinsicWidth() * f[Matrix.MSCALE_X]);
imageScaledHeight = Math.round(getDrawable().getIntrinsicHeight() * f[Matrix.MSCALE_Y]);
return (point.x>=(center.x-(imageScaledWidth/2))&&point.x<=(center.x+(imageScaledWidth/2))&&point.y>=(center.y-(imageScaledHeight/2))&&point.y<=(center.y+(imageScaledHeight/2)))?true:false;
}
private void adjustRectangle(int x, int y) {
int movement;
switch(getAffectedSide(x,y)) {
case LEFT:
movement = x-leftTop.x;
if(isInImageRange(new PointF(leftTop.x+movement,leftTop.y+movement)))
leftTop.set(leftTop.x+movement,leftTop.y+movement);
break;
case TOP:
movement = y-leftTop.y;
if(isInImageRange(new PointF(leftTop.x+movement,leftTop.y+movement)))
leftTop.set(leftTop.x+movement,leftTop.y+movement);
break;
case RIGHT:
movement = x-rightBottom.x;
if(isInImageRange(new PointF(rightBottom.x+movement,rightBottom.y+movement)))
rightBottom.set(rightBottom.x+movement,rightBottom.y+movement);
break;
case BOTTOM:
movement = y-rightBottom.y;
if(isInImageRange(new PointF(rightBottom.x+movement,rightBottom.y+movement)))
rightBottom.set(rightBottom.x+movement,rightBottom.y+movement);
break;
case DRAG:
movement = x-previous.x;
int movementY = y-previous.y;
if(isInImageRange(new PointF(leftTop.x+movement,leftTop.y+movementY)) && isInImageRange(new PointF(rightBottom.x+movement,rightBottom.y+movementY))) {
leftTop.set(leftTop.x+movement,leftTop.y+movementY);
rightBottom.set(rightBottom.x+movement,rightBottom.y+movementY);
}
break;
}
}
private static int getAffectedSide(float x, float y) {
int buffer = 10;
if(x>=(leftTop.x-buffer)&&x<=(leftTop.x+buffer))
return LEFT;
else if(y>=(leftTop.y-buffer)&&y<=(leftTop.y+buffer))
return TOP;
else if(x>=(rightBottom.x-buffer)&&x<=(rightBottom.x+buffer))
return RIGHT;
else if(y>=(rightBottom.y-buffer)&&y<=(rightBottom.y+buffer))
return BOTTOM;
else
return DRAG;
}
public byte[] getCroppedImage() {
BitmapDrawable drawable = (BitmapDrawable)getDrawable();
float x = leftTop.x-center.x+(drawable.getBitmap().getWidth()/2);
float y = leftTop.y-center.y+(drawable.getBitmap().getHeight()/2);
Bitmap cropped = Bitmap.createBitmap(drawable.getBitmap(),(int)x,(int)y,(int)rightBottom.x-(int)leftTop.x,(int)rightBottom.y-(int)leftTop.y);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
cropped.compress(Bitmap.CompressFormat.PNG, 100, stream);
return stream.toByteArray();
}
}
公共类CropView扩展了ImageView{
油漆=新油漆();
私有int初始_大小=300;
私有静态点leftTop、rightBottom、center、previous;
私有静态最终整数拖动=0;
私有静态final int LEFT=1;
专用静态最终int TOP=2;
私有静态最终整数右=3;
私有静态最终int-BOTTOM=4;
私有int imageScaledWidth、imageScaledHeight;
//添加父类构造函数
公共CropView(上下文){
超级(上下文);
initCropView();
}
公共CropView(上下文、属性集属性){
超级(上下文,属性,0);
initCropView();
}
公共CropView(上下文、属性集属性、int-defStyle){
超级(上下文、属性、定义样式);
initCropView();
}
@凌驾
受保护的void onDraw(画布)
{
super.onDraw(帆布);
if(leftTop.equals(0,0))
重置点();
drawRect(leftTop.x,leftTop.y,righbottom.x,righbottom.y,paint);
}
@凌驾
公共布尔onTouchEvent(运动事件){
int eventaction=event.getAction();
开关(事件操作){
case MotionEvent.ACTION\u DOWN:
set((int)event.getX(),(int)event.getY());
打破
case MotionEvent.ACTION\u移动:
if(isActionInsideRectangle(event.getX(),event.getY()){
adjustRectangle((int)event.getX(),(int)event.getY());
无效();//重新绘制矩形
set((int)event.getX(),(int)event.getY());
}
打破
case MotionEvent.ACTION\u UP:
上一个=新点();
打破
}
返回true;
}
私有void initCropView(){
油漆。设置颜色(颜色。黄色);
油漆.设置样式(样式.笔划);
油漆。设置行程宽度(5);
leftTop=新点();
右下=新点();
中心=新点();
上一个=新点();
}
公共无效重置点(){
center.set(getWidth()/2,getHeight()/2);
设置((getWidth()-初始大小)/2,(getHeight()-初始大小)/2);
设置(leftTop.x+初始大小,leftTop.y+初始大小);
}
私有静态布尔isActionInsideRectangle(浮点x,浮点y){
int缓冲区=10;
return(x>=(leftTop.x-buffer)和&x=(leftTop.y-buffer)和&y=(center.x-(imageScaledWidth/2))&&point.x=(center.y-(imageScaledHeight/2))&&point.y=(leftTop.x-buffer)和&x=(rightBottom.x-buffer)和&x=(rightBottom.y-buffer)和&y谢谢Hippo…但我已经解决了通过布局找到视图的问题
Uri imageUri = getIntent().getExtras().getParcelable("path");
b = (BitmapDrawable) BitmapDrawable.createFromPath(getRealPathFromURI(imageUri));
myCropView = (CropView) findViewById(R.id.image_preview);
myCropView.setBackground(b);
但现在我无法处理触摸事件。即使我触摸屏幕,矩形仍保持静止
编辑:好的,我已经让它工作了。但是现在,矩形只在一个较小的区域内移动,而不是在整个图像中。我想这里有问题
private boolean isInImageRange(PointF point) {
// Get image matrix values and place them in an array
float[] f = new float[9];
getImageMatrix().getValues(f);
// Calculate the scaled dimensions
imageScaledWidth = Math.round(getBackground().getIntrinsicWidth() * f[Matrix.MSCALE_X]);
imageScaledHeight = Math.round(getBackground().getIntrinsicHeight() * f[Matrix.MSCALE_Y]);
return (point.x>=(center.x-(imageScaledWidth/2))&&point.x<=(center.x+(imageScaledWidth/2))&&point.y>=(center.y-(imageScaledHeight/2))&&point.y<=(center.y+(imageScaledHeight/2)))?true:false;
}
private boolean isInImageRange(点F点){
//获取图像矩阵值并将其放入数组中
浮动[]f=新浮动[9];
getImageMatrix().getValues(f);
//计算缩放尺寸
imageScaledWidth=Math.round(getBackground().getIntrinsicWidth()*f[Matrix.MSCALE_X]);
imageScaledHeight=Math.round(getBackground().getIntrinsicHeight()*f[Matrix.MSCALE_Y]);
返回(point.x>=(center.x-(imageScaledWidth/2))&&point.x=(center.y-(imageScaledHeight/2))&&point.y您应该尝试:
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.crop_layout);
myCropView = new CropView(this);
Uri imageUri = getIntent().getExtras().getParcelable("path");
b = (BitmapDrawable) BitmapDrawable.createFromPath(imageUri.getPath());
myCropView.setImageURI(imageUri);
}
(摘自对您的问题的编辑。)我发现了一个支持此功能的库:SimpleCropView from。一般来说,我不推荐它,它的性能与本机android裁剪应用相去甚远
我尝试过使用它,我的想法是:
- 在你的应用程序中实现非常简单,我花了大约5分钟的时间在我现有的应用程序中实现裁剪和旋转功能
- 作物面积的重新调整非常缓慢,我不希望我的用户看到它
更新:
事实上,我在Github上找到了一个非常好的解决方案,如jdamcd/android crop:
总结:
- 在应用程序中使用非常简单
- 速度很快,因为它使用了本机gallery应用程序中的代码
- 可自定义,如果你想花一些时间玩它。默认情况下,它为你提供了一个可以进行裁剪的活动。如果你想将它集成到你自己的活动中,它将花费更多的时间。(对于我的项目,我本来希望集成它,将来也会这样做,但现在一个单独的活动就足够了)
希望这能提供一些见解!hi@Vahn84!很抱歉,我让你对代码感到困惑。你是如何解决你的问题的?我在线程中迷失了方向。还感谢@TheHippo的建议。我认为他的答案是设置图像的最佳方式。任何人都可以编辑最终代码,并且按照上面的方式??Hippo发布的代码工作吗是我用了错误的方法!b=(BitmapDrawable)BitmapDrawable.createFromPath(imageUri.getPath())有什么用
??@theHippo我如何在我的活动中使用我使用了上面的代码,但是裁剪的图像没有得到正确的显示,它正在缩放。同样的问题它没有在矩形的范围内裁剪图像。它如何缩放。我尝试了@theHippo回答仍然是同样的问题。但是我是否应该使用此代码我真的很喜欢你实现它的方式他的自定义裁剪器带有imageview。你找不到扩展imageview的自定义裁剪器。但是,有一件事,你找到了一种方法来
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.crop_layout);
myCropView = new CropView(this);
Uri imageUri = getIntent().getExtras().getParcelable("path");
b = (BitmapDrawable) BitmapDrawable.createFromPath(imageUri.getPath());
myCropView.setImageURI(imageUri);
}