当前位置: 移动技术网 > IT编程>移动开发>Android > Android 以任意比例裁剪图片代码分享

Android 以任意比例裁剪图片代码分享

2019年07月24日  | 移动技术网IT编程  | 我要评论

重生之正妻攻略,酒精比重计,csolsk

公司的一个小伙伴写的,可以按照任意比例裁剪图片。我觉得挺好用的。简单在这里记录一下,以后肯定还会用到。

public class seniorcropimageview extends imageview implements scalegesturedetector.onscalegesturelistener, 
view.onlayoutchangelistener { 
/* for drawing color field start */ 
private static final int line_color = color.white; 
private static final int outer_mask_color = color.argb(191, 0, 0, 0); 
private static final int line_width_in_dp = 1; 
private final float[] mmatrixvalues = new float[9]; 
protected matrix msupportmatrix; 
protected scalegesturedetector mscalegesturedetector; 
/* for drawing color field end */ 
protected paint mpaint; 
/* 
* 宽比高 
*/ 
protected float mratio = 1.0f; 
protected rectf mcroprect; 
//rectfpadding是适应产品需求,给裁剪框mcroprect设置一下padding -- chenglin 2016年04月18日 
protected float rectfpadding = 0; 
protected int mlastx; 
protected int mlasty; 
protected operation moperation; 
private onbitmaploadlistener ibitmaploading = null; 
private boolean menabledrawcropwidget = true; 
/* 
for scale and drag 
*/ 
private matrix mbasematrix; 
private matrix mdrawmatrix; 
private acceleratedecelerateinterpolator sinterpolator = new acceleratedecelerateinterpolator(); 
private path mpath; 
private int mlinewidth; 
private float mscalemax = 3.0f; 
private rectf mboundaryrect; 
private int mrotation = 0; 
private int mimagewidth; 
private int mimageheight; 
private int mdisplayw; 
private int mdisplayh; 
public seniorcropimageview(context context) { 
this(context, null); 
} 
public seniorcropimageview(context context, attributeset attrs) { 
this(context, attrs, 0); 
} 
public seniorcropimageview(context context, attributeset attrs, int defstyleattr) { 
super(context, attrs, defstyleattr); 
if (attrs != null) { 
typedarray a = context.obtainstyledattributes(attrs, r.styleable.life_cropimage); 
mratio = a.getfloat(r.styleable.life_cropimage_life_crop_ratio, 1.0f); 
a.recycle(); 
} 
init(); 
} 
public static void decodeimageforcropping(final string path, final idecodecallback callback) { 
new thread(new runnable() { 
@override 
public void run() { 
int rotation = 0; 
// 读取一下exif中的rotation 
try { 
exifinterface exif = new exifinterface(path); 
final int rotate = exif.getattributeint(exifinterface.tag_orientation, exifinterface.orientation_undefined); 
switch (rotate) { 
case exifinterface.orientation_rotate_90: 
rotation = 90; 
break; 
case exifinterface.orientation_rotate_180: 
rotation = 180; 
break; 
case exifinterface.orientation_rotate_270: 
rotation = 270; 
break; 
} 
} catch (ioexception e) { 
e.printstacktrace(); 
} 
final bitmapfactory.options options = new bitmapfactory.options(); 
options.injustdecodebounds = true; 
bitmapfactory.decodefile(path, options); 
final int texturelimit = getmaxtexturesize(); 
int scale = 1; 
while (options.outwidth / scale >= texturelimit) { 
scale *= 2; 
} 
while (options.outheight / scale >= texturelimit) { 
scale *= 2; 
} 
options.insamplesize = scale; 
options.injustdecodebounds = false; 
bitmap bitmap = null; 
try { 
bitmap = bitmapfactory.decodefile(path, options); 
} catch (outofmemoryerror e) { 
e.printstacktrace(); 
} 
final bitmap bimapdecoded = bitmap; 
if (bimapdecoded == null) { 
return; 
} 
if (callback != null) { 
callback.ondecoded(rotation, bimapdecoded); 
} 
} 
}).start(); 
} 
private static int getmaxtexturesize() { 
egl10 egl = (egl10) eglcontext.getegl(); 
egldisplay display = egl.eglgetdisplay(egl10.egl_default_display); 
// initialise 
int[] version = new int[2]; 
egl.eglinitialize(display, version); 
// query total number of configurations 
int[] totalconfigurations = new int[1]; 
egl.eglgetconfigs(display, null, 0, totalconfigurations); 
// query actual list configurations 
eglconfig[] configurationslist = new eglconfig[totalconfigurations[0]]; 
egl.eglgetconfigs(display, configurationslist, totalconfigurations[0], totalconfigurations); 
int[] texturesize = new int[1]; 
int maximumtexturesize = 0; 
// iterate through all the configurations to located the maximum texture size 
for (int i = 0; i < totalconfigurations[0]; i++) { 
// only need to check for width since opengl textures are always squared 
egl.eglgetconfigattrib(display, configurationslist[i], egl10.egl_max_pbuffer_width, texturesize); 
// keep track of the maximum texture size 
if (maximumtexturesize < texturesize[0]) { 
maximumtexturesize = texturesize[0]; 
} 
} 
// release 
egl.eglterminate(display); 
return maximumtexturesize; 
} 
@override 
public void onlayoutchange(view v, int left, int top, int right, int bottom, int oldleft, int oldtop, int oldright, int oldbottom) { 
mdisplayw = right - left; 
mdisplayh = bottom - top; 
if (getdrawable() != null && ((bitmapdrawable) getdrawable()).getbitmap() != null) { 
calculateproperties(((bitmapdrawable) getdrawable()).getbitmap()); 
} 
} 
private void init() { 
mscalegesturedetector = new scalegesturedetector(getcontext(), this); 
mbasematrix = new matrix(); 
mdrawmatrix = new matrix(); 
msupportmatrix = new matrix(); 
mlinewidth = (int) diptopixels(line_width_in_dp); 
mpaint = new paint(); 
// 表示第一个实线段长dashonwidth,第一个虚线段长dashoffwidth 
mpath = new path(); 
mcroprect = new rectf(); 
mboundaryrect = new rectf(); 
setscaletype(scaletype.matrix); 
setclickable(true); 
} 
private float diptopixels(float dip) { 
return typedvalue.applydimension(typedvalue.complex_unit_dip, dip, 
getresources().getdisplaymetrics()); 
} 
@override 
protected void onattachedtowindow() { 
super.onattachedtowindow(); 
addonlayoutchangelistener(this); 
} 
@override 
protected void ondetachedfromwindow() { 
super.ondetachedfromwindow(); 
removeonlayoutchangelistener(this); 
} 
/** 
* 设置图片的裁剪比例,比如3:4就是0.75 
* 
* @param ratio 
*/ 
public void setcropratio(final float ratio) { 
if (mratio == ratio) { 
return; 
} 
mratio = ratio; 
//重新选择比例后,恢复旋转角度 
//setimagerotation(0); 
if (getdrawable() == null) { 
return; 
} 
calculateproperties(((bitmapdrawable) getdrawable()).getbitmap()); 
postinvalidate(); 
} 
public void setimagerotation(int rotation) { 
if (mrotation == rotation) { 
return; 
} 
mrotation = rotation; 
if (getdrawable() == null) { 
return; 
} 
calculateproperties(((bitmapdrawable) getdrawable()).getbitmap()); 
postinvalidate(); 
} 
public void setcroprectpadding(float padding) { 
rectfpadding = padding; 
} 
public void setimagepath(final string path) { 
if (textutils.isempty(path)) { 
return; 
} 
if (ibitmaploading != null) { 
ibitmaploading.onloadprepare(); 
} 
decodeimageforcropping(path, new idecodecallback() { 
@override 
public void ondecoded(final int rotation, final bitmap bitmap) { 
post(new runnable() { 
@override 
public void run() { 
mrotation = rotation; 
setimagebitmap(bitmap); 
if (ibitmaploading != null) { 
ibitmaploading.onloadfinish(); 
} 
} 
}); 
} 
}); 
} 
@override 
public void setimagebitmap(bitmap bm) { 
calculateproperties(bm); 
super.setimagebitmap(bm); 
} 
public void setbitmaploadinglistener(onbitmaploadlistener ibitmapload) { 
ibitmaploading = ibitmapload; 
} 
protected void calculateproperties(bitmap bm) { 
msupportmatrix.reset(); 
mbasematrix.reset(); 
int widthsize = mdisplayw; 
int heightsize = mdisplayh; 
generatecroprect(widthsize, heightsize); 
mimagewidth = bm.getwidth(); 
mimageheight = bm.getheight(); 
final boolean rotated = isimagerotated(); 
final int bitmapwidth = rotated ? mimageheight : mimagewidth; 
final int bitmapheight = rotated ? mimagewidth : mimageheight; 
mboundaryrect.set(0, 0, bitmapwidth, bitmapheight); 
final float widthscale = mcroprect.width() / bitmapwidth; 
final float heightscale = mcroprect.height() / bitmapheight; 
final float scale = math.max(widthscale, heightscale); 
final float scaledheight = scale * bitmapheight; 
final float scaledwidth = scale * bitmapwidth; 
// 移动到中心点 
final int translatex = (int) (mcroprect.left + mcroprect.width() / 2 - scaledwidth / 2); 
final int translatey = (int) (mcroprect.top + mcroprect.height() / 2 - scaledheight / 2); 
mbasematrix.setscale(scale, scale); 
mbasematrix.posttranslate(translatex, translatey); 
mbasematrix.maprect(mboundaryrect); 
setimagematrix(getdrawmatrix()); 
} 
private boolean isimagerotated() { 
return ((mrotation % 360) == 90) || ((mrotation % 360) == 270); 
} 
private void generatecroprect(int boundarywidth, int boundaryheight) { 
//rectfpadding是适应产品需求,给裁剪框mcroprect设置一下padding -- chenglin 2016年04月18日 
boundarywidth = boundarywidth - (int)(rectfpadding * 2); 
boundaryheight = boundaryheight - (int)(rectfpadding * 2); 
int left; 
int top; 
int right; 
int bottom; 
boolean vertical; 
// 宽/高 大于比例的话,说明裁剪框是“竖直”的 
vertical = (float) boundarywidth / boundaryheight > mratio; 
final int recth = (int) (boundarywidth / mratio); 
final int rectw = (int) (boundaryheight * mratio); 
if (vertical) { 
left = (boundarywidth - rectw) / 2; 
top = 0; 
right = (boundarywidth + rectw) / 2; 
bottom = boundaryheight; 
} else { 
left = 0; 
top = (boundaryheight - recth) / 2; 
right = boundarywidth; 
bottom = (boundaryheight + recth) / 2; 
} 
//rectfpadding是适应产品需求,给裁剪框mcroprect设置一下padding -- chenglin 2016年04月18日 
mcroprect.set(left + rectfpadding, top + rectfpadding, right + rectfpadding, bottom + rectfpadding); 
} 
@override 
protected void ondraw(canvas canvas) { 
super.ondraw(canvas); 
if (!menabledrawcropwidget) { 
return; 
} 
if (getdrawable() == null) { 
return; 
} 
mpaint.reset(); 
mpaint.setantialias(true); 
mpaint.setcolor(line_color); 
mpaint.setstrokewidth(mlinewidth); 
mpaint.setstyle(paint.style.stroke); 
mpath.reset(); 
// 上 
mpath.moveto(mcroprect.left, mcroprect.top); 
mpath.lineto(mcroprect.right, mcroprect.top); 
// 左 
mpath.moveto(mcroprect.left, mcroprect.top); 
mpath.lineto(mcroprect.left, mcroprect.bottom); 
// 右 
mpath.moveto(mcroprect.right, mcroprect.top); 
mpath.lineto(mcroprect.right, mcroprect.bottom); 
// 下 
mpath.moveto(mcroprect.right, mcroprect.bottom); 
mpath.lineto(mcroprect.left, mcroprect.bottom); 
canvas.drawpath(mpath, mpaint); 
// 绘制外部阴影部分 
mpaint.reset(); 
mpaint.setantialias(true); 
mpaint.setcolor(color.parsecolor("#b3333333")); 
mpaint.setstyle(paint.style.fill); 
//下面的四个矩形是装饰性的,就是裁剪框四周的四个阴影 
final int lineoffset = mlinewidth; 
if (mcroprect.top > 0) { 
canvas.drawrect(0, 0, getmeasuredwidth(), mcroprect.top - lineoffset, mpaint); 
} 
if (mcroprect.left > 0) { 
canvas.drawrect(mcroprect.top - lineoffset - rectfpadding, rectfpadding - lineoffset, mcroprect.left - lineoffset, mcroprect.bottom + lineoffset, mpaint); 
} 
if (mcroprect.right < getmeasuredwidth()) { 
canvas.drawrect(mcroprect.right + lineoffset, mcroprect.top - lineoffset, getmeasuredwidth(), mcroprect.bottom + lineoffset, mpaint); 
} 
if (mcroprect.bottom < getmeasuredheight()) { 
canvas.drawrect(0, mcroprect.bottom + lineoffset, getmeasuredwidth(), getmeasuredheight(), mpaint); 
} 
} 
public boolean ontouchevent(motionevent ev) { 
if (ev.getpointercount() > 1) { 
moperation = operation.scale; 
return mscalegesturedetector.ontouchevent(ev); 
} 
final int action = ev.getactionmasked(); 
final int x = (int) ev.getx(); 
final int y = (int) ev.gety(); 
switch (action) { 
case motionevent.action_down: 
moperation = operation.drag; 
mlastx = x; 
mlasty = y; 
break; 
case motionevent.action_move: 
if (moperation == operation.drag) { 
int deltax = x - mlastx; 
int deltay = y - mlasty; 
rectf boundary = getdrawboundary(getdrawmatrix()); 
if (boundary.left + deltax > mcroprect.left) { 
deltax = (int) (mcroprect.left - boundary.left); 
} else if (boundary.right + deltax < mcroprect.right) { 
deltax = (int) (mcroprect.right - boundary.right); 
} 
if (boundary.top + deltay > mcroprect.top) { 
deltay = (int) (mcroprect.top - boundary.top); 
} else if (boundary.bottom + deltay < mcroprect.bottom) { 
deltay = (int) (mcroprect.bottom - boundary.bottom); 
} 
msupportmatrix.posttranslate(deltax, deltay); 
setimagematrix(getdrawmatrix()); 
mlastx = x; 
mlasty = y; 
} 
break; 
case motionevent.action_cancel: 
case motionevent.action_pointer_up: 
case motionevent.action_up: 
mlastx = 0; 
mlasty = 0; 
moperation = null; 
break; 
} 
return super.ontouchevent(ev); 
} 
public bitmap getoriginbitmap() { 
bitmapdrawable drawable = (bitmapdrawable) getdrawable(); 
return drawable == null ? null : drawable.getbitmap(); 
} 
/** 
* 保存图片为bitmap 
*/ 
public bitmap savecrop() throws outofmemoryerror { 
if (getdrawable() == null) { 
return null; 
} 
bitmap origin = getoriginbitmap(); 
matrix drawmatrix = getdrawmatrix(); 
// 反转一下矩阵 
matrix inverse = new matrix(); 
drawmatrix.invert(inverse); 
// 把裁剪框对应到原图上去 
rectf cropmapped = new rectf(); 
inverse.maprect(cropmapped, mcroprect); 
clampcroprect(cropmapped, origin.getwidth(), origin.getheight()); 
// 如果产生了旋转,需要一个旋转矩阵 
matrix rotationm = new matrix(); 
if (mrotation % 360 != 0) { 
rotationm.postrotate(mrotation, origin.getwidth() / 2, origin.getheight() / 2); 
} 
bitmap cropped = bitmap.createbitmap( 
origin, (int) cropmapped.left, (int) cropmapped.top, (int) cropmapped.width(), (int) cropmapped.height(), rotationm, true 
); 
return cropped; 
} 
private void clampcroprect(rectf croprect, int borderw, int borderh) { 
if (croprect.left < 0) { 
croprect.left = 0; 
} 
if (croprect.top < 0) { 
croprect.top = 0; 
} 
if (croprect.right > borderw) { 
croprect.right = borderw; 
} 
if (croprect.bottom > borderh) { 
croprect.bottom = borderh; 
} 
} 
@override 
public boolean onscale(scalegesturedetector detector) { 
float scale = detector.getscalefactor(); 
if (scale == 1.0f) { 
return true; 
} 
final float currentscale = getscale(msupportmatrix); 
final float centerx = detector.getfocusx(); 
final float centery = detector.getfocusy(); 
if ((currentscale <= 1.0f && scale < 1.0f) 
|| (currentscale >= mscalemax && scale > 1.0f)) { 
return true; 
} 
if (currentscale * scale < 1.0f) { 
scale = 1.0f / currentscale; 
} else if (currentscale * scale > mscalemax) { 
scale = mscalemax / currentscale; 
} 
msupportmatrix.postscale(scale, scale, centerx, centery); 
rectf boundary = getdrawboundary(getdrawmatrix()); 
float translatex = 0; 
if (boundary.left > mcroprect.left) { 
translatex = mcroprect.left - boundary.left; 
} else if (boundary.right < mcroprect.right) { 
translatex = mcroprect.right - boundary.right; 
} 
log.d("scale", "x==>" + translatex); 
float translatey = 0; 
if (boundary.top > mcroprect.top) { 
translatey = mcroprect.top - boundary.top; 
} else if (boundary.bottom < mcroprect.bottom) { 
translatey = mcroprect.bottom - boundary.bottom; 
} 
msupportmatrix.posttranslate(translatex, translatey); 
setimagematrix(getdrawmatrix()); 
return true; 
} 
protected matrix getdrawmatrix() { 
mdrawmatrix.reset(); 
if (mrotation % 360 != 0) { 
final boolean rotated = isimagerotated(); 
final int width = rotated ? mimageheight : mimagewidth; 
final int height = rotated ? mimagewidth : mimageheight; 
mdrawmatrix.postrotate(mrotation, mimagewidth / 2, mimageheight / 2); 
if (rotated) { 
final int translatex = (width - mimagewidth) / 2; 
final int translatey = (height - mimageheight) / 2; 
mdrawmatrix.posttranslate(translatex, translatey); 
} 
} 
mdrawmatrix.postconcat(mbasematrix); 
mdrawmatrix.postconcat(msupportmatrix); 
return mdrawmatrix; 
} 
@override 
public boolean onscalebegin(scalegesturedetector detector) { 
return true; 
} 
@override 
public void onscaleend(scalegesturedetector detector) { 
final float currentscale = getscale(msupportmatrix); 
if (currentscale < 1.0f) { 
log.e("onscaleend", "currentscale==>" + currentscale); 
rectf boundary = getdrawboundary(getdrawmatrix()); 
post(new animatedzoomrunnable(currentscale, 1.0f, boundary.centerx(), boundary.centery())); 
} 
} 
protected rectf getdrawboundary(matrix matrix) { 
drawable drawable = getdrawable(); 
if (drawable == null) { 
return mboundaryrect; 
} 
final int bitmapwidth = drawable.getintrinsicwidth(); 
final int bitmapheight = drawable.getintrinsicheight(); 
mboundaryrect.set(0, 0, bitmapwidth, bitmapheight); 
matrix.maprect(mboundaryrect); 
return mboundaryrect; 
} 
public float getscale(matrix matrix) { 
return (float) math.sqrt((float) math.pow(getvalue(matrix, matrix.mscale_x), 2) + (float) math.pow(getvalue(matrix, matrix.mskew_y), 2)); 
} 
/** 
* helper method that 'unpacks' a matrix and returns the required value 
* 
* @param matrix - matrix to unpack 
* @param whichvalue - which value from matrix.m* to return 
* @return float - returned value 
*/ 
private float getvalue(matrix matrix, int whichvalue) { 
matrix.getvalues(mmatrixvalues); 
return mmatrixvalues[whichvalue]; 
} 
public void enabledrawcropwidget(boolean enable) { 
menabledrawcropwidget = enable; 
} 
protected enum operation { 
drag, scale 
} 
public enum type { 
center_crop, center_inside 
} 
public interface idecodecallback { 
void ondecoded(final int rotation, final bitmap bitmap); 
} 
//setimagepath这个方法耗时,需要显示进度条,这个是监听 
public interface onbitmaploadlistener { 
void onloadprepare(); 
void onloadfinish(); 
} 
private class animatedzoomrunnable implements runnable { 
private final float mfocalx, mfocaly; 
private final long mstarttime; 
private final float mzoomstart, mzoomend; 
public animatedzoomrunnable(final float currentzoom, final float targetzoom, 
final float focalx, final float focaly) { 
mfocalx = focalx; 
mfocaly = focaly; 
mstarttime = system.currenttimemillis(); 
mzoomstart = currentzoom; 
mzoomend = targetzoom; 
} 
@override 
public void run() { 
float t = interpolate(); 
float scale = mzoomstart + t * (mzoomend - mzoomstart); 
float deltascale = scale / getscale(msupportmatrix); 
msupportmatrix.postscale(deltascale, deltascale, mfocalx, mfocaly); 
setimagematrix(getdrawmatrix()); 
// we haven't hit our target scale yet, so post ourselves again 
if (t < 1f) { 
postonanimation(this); 
} 
} 
private float interpolate() { 
float t = 1f * (system.currenttimemillis() - mstarttime) / 200; 
t = math.min(1f, t); 
t = sinterpolator.getinterpolation(t); 
return t; 
} 
} 
} 
<declare-styleable name="life_cropimage"> 
<attr name="life_crop_ratio" format="float" /> 
<attr name="life_crop_scale_type" format="enum"> 
<enum name="life_center_crop" value="0" /> 
<enum name="life_center_inside" value="1" /> 
</attr> 
</declare-styleable>

1、让这个裁剪框显示图片:

mseniorimageview.setimagepath(path);

2、保存裁剪后的图片:

bitmap imageviewbitmap = null; 
try { 
imageviewbitmap = mseniorimageview.savecrop(); 
} catch (outofmemoryerror e) { 
imageviewbitmap = mseniorimageview.getoriginbitmap(); 
pinktoast.maketext(mactivity, r.string.life_image_crop_topbar_crop_error, toast.length_long).show(); 
}

3、设置裁剪比例:

mseniorimageview.setcropratio(3f / 4f);

4、设置裁剪框的padding:

mseniorimageview.setcroprectpadding(0f);

5、setimagepath这个方法比较耗时,需要显示进度条,这个是监听:

mseniorimageview.setbitmaploadinglistener(new seniorcropimageview.onbitmaploadlistener() { 
@override 
public void onloadprepare() { 
mactivity.showprogress(); 
} 
@override 
public void onloadfinish() { 
mactivity.hideprogress(); 
} 
});

以上所述是小编给大家带来的android 以任意比例裁剪图片代码分享,希望对大家有所帮助

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网