Camera图片特效处理综述(Bitmap的Pixels处理、Canvas/paint的drawBitmap处理、旋转图片、裁截图片、播放幻灯片浏览图片<线程固定时间显示一张>)
一种是直接对Bitmap的像素进行操作,如:叠加、边框、怀旧、(高斯)模糊、锐化(拉普拉斯变换)。
Bitmap.getPixels(srcPixels, 0, width, 0, 0, width, height);
newR = (int) (pixR * alpha + layR * (1 - alpha));
newR = Math.min(255, Math.max(0, newR));
。。。
srcPixels[pos] = Color.argb(newA, newR, newG, newB);
Bitmap.setPixels(srcPixels, 0, width, 0, 0, width, height);
另一种是使用画布Canvas自带的函数进行处理,如:圆角、倒影、色相、饱和度、亮度、涂鸦:
Canvas canvas = new Canvas();//创建 空白画布,或new Canvas(bitmap)创建有背景画布,根据情况选择
Paint paint = new Paint();
。。。
canvas.drawBitmap(bitmap, null, rect, paint);
使用画布Canvas自带的函数进行处理的代码,以圆角特效为例:
//圆角特效 public static Bitmap getRoundCornerImage(Bitmap bitmap, int roundPixels, int width, int height ) { //创建一个和原始图片一样大小位图 Bitmap roundConcerImage = Bitmap.createBitmap(width, height, Config.ARGB_8888); //创建带有位图roundConcerImage的画布 Canvas canvas = new Canvas(roundConcerImage); //创建画笔 Paint paint = new Paint(); //创建一个和原始图片一样大小的矩形 Rect rect = new Rect(0, 0, width, height); RectF rectF = new RectF(rect); // 去锯齿 paint.setAntiAlias(true); //画一个和原始图片一样大小的圆角矩形 canvas.drawRoundRect(rectF, roundPixels, roundPixels, paint); //设置相交模式 paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); //把图片画到矩形去 canvas.drawBitmap(bitmap, null, rect, paint); return roundConcerImage; }
直接对Bitmap的像素进行处理的代码,以怀旧特效为例:
Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { Drawable targetBitmapDrawable = new BitmapDrawable((Bitmap) msg.obj);// 将Bitmap转换为Drawable is.setImageDrawable(targetBitmapDrawable); } }; /** * 怀旧效果 * @param bmp * @return */ private void oldRemeber(final Bitmap bmp) { Thread thread = new Thread() { @Override public void run() { int width = bmp.getWidth(); int height = bmp.getHeight(); Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); int pixColor = 0; int pixR = 0; int pixG = 0; int pixB = 0; int newR = 0; int newG = 0; int newB = 0; int[] pixels = new int[width * height]; bmp.getPixels(pixels, 0, width, 0, 0, width, height); for (int i = 0; i < height; i++) { for (int k = 0; k < width; k++) { pixColor = pixels[width * i + k]; pixR = Color.red(pixColor); pixG = Color.green(pixColor); pixB = Color.blue(pixColor); newR = (int) (0.393 * pixR + 0.769 * pixG + 0.189 * pixB); newG = (int) (0.349 * pixR + 0.686 * pixG + 0.168 * pixB); newB = (int) (0.272 * pixR + 0.534 * pixG + 0.131 * pixB); int newColor = Color.argb(255, newR > 255 ? 255 : newR, newG > 255 ? 255 : newG, newB > 255 ? 255 : newB); pixels[width * i + k] = newColor; } } bitmap.setPixels(pixels, 0, width, 0, 0, width, height); Message message = handler.obtainMessage(); message.obj = bitmap; handler.sendMessage(message); } }; thread.start(); thread = null; }
涂鸦特效再说明:
canvas = new Canvas(originalBitmap);//以原图片为背景创建画布
canvas.drawLine(startX, startY, clickX, clickY, paint);//根据手指移动画线条
canvas.drawBitmap(finalBitmap, 0, 0,null);//
左右旋转图片再说明:
File MatrixLeftFile=new File(currentImagePath); try { BitmapOrgLeft = BitmapFactory.decodeStream(new FileInputStream(MatrixLeftFile), null, RotateOptions); } catch (FileNotFoundException e2) { // TODO 自动生成的 catch 块 e2.printStackTrace(); } BitmapOrgLeft = Bitmap.createBitmap(BitmapOrgLeft, 0, 0, BitmapOrgLeft.getWidth(), BitmapOrgLeft.getHeight(), matrixleft, true); try { bos = new BufferedOutputStream(new FileOutputStream(MatrixLeftFile)); } catch (FileNotFoundException e1) { // TODO 自动生成的 catch 块 e1.printStackTrace(); } /* 采用压缩转档方法 */ BitmapOrgLeft.compress(Bitmap.CompressFormat.JPEG, 100, bos); /* 调用flush()方法,更新BufferStream */ try { bos.flush(); } catch (IOException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } /* 结束OutputStream */ try { bos.close(); } catch (IOException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } imageAdapter.notifyDataSetChanged(); //调用函数刷新图片 Refresh_Rotating_Pictures(); Toast.makeText(getBaseContext(), "保存成功!", Toast.LENGTH_LONG).show(); //及时的释放 Bitmap 对象 if(BitmapOrgLeft != null && !BitmapOrgLeft.isRecycled()) { BitmapOrgLeft.recycle(); BitmapOrgLeft = null; }
裁截图片再说明:
主要是两个函数和画布canvas的使用:
public void moveChooseArea(int move_x,int move_y){}:整体调整矩形的四条边,有最大最小限制。
private void pressLB(int x,int y)、 pressLT、 pressRB、 pressRT:调整相邻的某(左、上)两条边,有最大最小限制。
canvas.drawRect(ChooseArea, mPaint);
mPaint.setColor(Color.BLUE);
canvas.drawRect(recLT, mPaint);
canvas.drawRect(recLB, mPaint);
canvas.drawRect(recRT, mPaint);
canvas.drawRect(recRB, mPaint);
canvas.drawRect(leftRectL, leftAreaPaint);
canvas.drawRect(leftRectR, leftAreaPaint);
canvas.drawRect(leftRectT, leftAreaPaint);
canvas.drawRect(leftRectB, leftAreaPaint);
package com.cutPicture; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.RectF; import android.graphics.Bitmap.Config; import android.graphics.drawable.BitmapDrawable; import android.util.AttributeSet; import android.view.MotionEvent; import android.widget.ImageView; //http://www.cdtarena.com/gpx/201305/8653.html public class MyCutView extends ImageView { private final static int PRESS_LB = 0;//表示左下角矩形框 private final static int PRESS_LT = 1;//表示左上角矩形框 private final static int PRESS_RB = 2;//表示右下角矩形框 private final static int PRESS_RT = 3;//表示右上角矩形框 private Bitmap bitMap = null; //原始图片 private RectF src = null; //经过比例转换后的裁剪区域 private RectF dst = null; //图片显示区域,也就是drawBitmap函数中的目标dst private RectF ChooseArea = null; //选择区域 private Paint mPaint = null; //画笔 private Matrix matrix = null; //矩阵 private int mx = 0; //存储触笔移动时,之前**的触笔的x坐标 private int my = 0; //存储触笔移动时,之前**的触笔的y坐标 private boolean touchFlag = false; //触笔是否在屏幕之*? private boolean cutFlag = false; //是否点击了menu上的裁剪按钮 private int recFlag = -1; //用来存储触笔点击了哪个小矩形框(改变选择区域大小的小矩形框) private boolean firstFlag = false; private RectF recLT = null; //左上角的小矩形框 private RectF recRT = null; //右上角的小矩形框 private RectF recLB = null; //左下角的小矩形框 private RectF recRB = null; //右下角的小矩形框 private static final int LEFT_AREA_ALPHA = 50 * 255 / 100; private RectF leftRectL = null; private RectF leftRectR = null; private RectF leftRectT = null; private RectF leftRectB = null; private Paint leftAreaPaint = null; int padding=0; public String editImagePath=null; public MyCutView(Context context, AttributeSet attrs) { super(context, attrs); this.init(); } public MyCutView(Context context) { super(context); this.init(); } public void init(){ cutFlag = true; recLT = new RectF(); recLB = new RectF(); recRT = new RectF(); recRB = new RectF(); dst = new RectF(); mPaint = new Paint(); mPaint.setColor(Color.RED); mPaint.setStyle(Paint.Style.STROKE); //将画笔的风格改为空心 ChooseArea = new RectF(); this.setPressRecLoc(); src = null; firstFlag = true; //选择框之外的灰色区域,分成四个矩形框 leftAreaPaint = new Paint(); leftAreaPaint.setStyle(Paint.Style.FILL); leftAreaPaint.setAlpha(MyCutView.LEFT_AREA_ALPHA); } public void setBitmap(Bitmap bitmap){ BitmapDrawable bd = new BitmapDrawable(bitmap); src = new RectF(0,0,bd.getIntrinsicWidth(),bd.getIntrinsicHeight()); this.bitMap = bitmap.copy(Config.ARGB_8888, true); this.setImageBitmap(bitMap); leftRectB = new RectF(); leftRectL = new RectF(); leftRectR = new RectF(); leftRectT = new RectF(); } public void imageScale(){ matrix = this.getImageMatrix(); matrix.mapRect(dst, src); padding = this.getPaddingBottom(); /* int width = bitMap.getWidth(); int height = bitMap.getHeight(); //dst.set(dst.left+padding,dst.top+padding,dst.right+padding,dst.bottom+padding); if(height>width) { dst.set(dst.left,dst.top,width-7,height+100); 适用于android:layout_width="wrap_content"是FillParent并且没有android:layout_centerInParent="true"属性 } else { dst.set(dst.left,dst.top,width-170,height+120); } */ int w=this.getWidth(); int h=this.getHeight(); //if(h>w) { dst.set(dst.left+2,dst.top+2,w-4,h-6); } //else if(editImagePath!=null) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(editImagePath, options); int tempH = options.outHeight; if(tempH==1944) { dst.set(dst.left+2,dst.top+2,w-4,h-67); } } ChooseArea = new RectF(dst); this.setPressRecLoc(); } public Bitmap getSubsetBitmap(){ float ratioWidth = bitMap.getWidth()/(float)(dst.right-dst.left); float ratioHeight = bitMap.getHeight()/(float)(dst.bottom - dst.top); int left = (int)((ChooseArea.left - dst.left) * ratioWidth); int right = (int)(left + (ChooseArea.right - ChooseArea.left) * ratioWidth); int top = (int)((ChooseArea.top - dst.top) * ratioHeight); int bottom = (int)(top + (ChooseArea.bottom - ChooseArea.top) * ratioHeight); src = new RectF(left,top,right,bottom); firstFlag = true; set_LeftArea_Alpha(); return Bitmap.createBitmap(bitMap, left, top, right-left, bottom-top); } //获得ChooseArea对象 public RectF getChooseArea(){ return ChooseArea; } public void moveChooseArea(int move_x,int move_y){ if(ChooseArea.left + move_x >= dst.left && ChooseArea.right + move_x <= dst.right && ChooseArea.top + move_y >= dst.top && ChooseArea.bottom + move_y <= dst.bottom){ ChooseArea.set(ChooseArea.left + move_x,ChooseArea.top+move_y ,ChooseArea.right + move_x,ChooseArea.bottom+move_y); }else{ if(ChooseArea.left + move_x < dst.left){ ChooseArea.set(dst.left,ChooseArea.top ,ChooseArea.right+dst.left-ChooseArea.left,ChooseArea.bottom); } if(ChooseArea.right + move_x > dst.right){ ChooseArea.set(ChooseArea.left+dst.right-ChooseArea.right,ChooseArea.top ,dst.right,ChooseArea.bottom); } if(ChooseArea.top + move_y < dst.top){ ChooseArea.set(ChooseArea.left,dst.top ,ChooseArea.right,ChooseArea.bottom+dst.top-ChooseArea.top); } if(ChooseArea.bottom + move_y > dst.bottom){ ChooseArea.set(ChooseArea.left,ChooseArea.top+dst.bottom-ChooseArea.bottom ,ChooseArea.right,dst.bottom); } } this.setPressRecLoc(); mPaint.setColor(Color.GREEN); this.invalidate(); } public boolean onTouchEvent(MotionEvent event){ mPaint.setColor(Color.RED); if(event.getAction() == MotionEvent.ACTION_DOWN && cutFlag){ //System.out.println(event.getX() + "," + event.getY()); mx = (int)event.getX(); my = (int)event.getY(); if(this.judgeLocation(mx,my)){ touchFlag = true; mPaint.setColor(Color.GREEN); this.invalidate(); return true; }else{ if(this.findPresseddst((int)event.getX(), (int)event.getY())){ touchFlag = true; mPaint.setColor(Color.RED); return true; } } } if(event.getAction() == MotionEvent.ACTION_MOVE && touchFlag){ //判断是否点击了哪个个小矩形框 if(this.isOutOfArea((int)event.getX(), (int)event.getY())){ return true; } //www.cdtarena.com如果选择区域大小跟图像大小一样时,就不能移动 if(ChooseArea.left == dst.left && ChooseArea.top == dst.top && ChooseArea.right == dst.right && ChooseArea.bottom == dst.bottom){ }else{ this.moveChooseArea((int)event.getX() - mx, (int)event.getY() - my); mx = (int)event.getX(); my = (int)event.getY(); } } if(event.getAction() == MotionEvent.ACTION_UP){ recFlag = -1; this.invalidate(); touchFlag = false; } return super.onTouchEvent(event); } private boolean isOutOfArea(int x,int y){ switch(recFlag){ case MyCutView.PRESS_LB: this.pressLB(x - mx, y - my); break; case MyCutView.PRESS_LT: this.pressLT(x - mx, y - my); break; case MyCutView.PRESS_RB: this.pressRB(x - mx, y - my); break; case MyCutView.PRESS_RT: this.pressRT(x - mx, y - my); break; default:return false; } mx = x; my = y; this.invalidate(); return true; } public boolean findPresseddst(int x,int y){ boolean returnFlag = false; if(this.isInRect(x, y, recLB)){ recFlag = MyCutView.PRESS_LB; returnFlag = true; }else if(this.isInRect(x, y, recLT)){ recFlag = MyCutView.PRESS_LT; returnFlag = true; }else if(this.isInRect(x, y, recRB)){ recFlag = MyCutView.PRESS_RB; returnFlag = true; }else if(this.isInRect(x, y, recRT)){ recFlag = MyCutView.PRESS_RT; returnFlag = true; } return returnFlag; } public boolean isInRect(int x,int y,RectF rect){ if(x >= rect.left -20 && x <= rect.right + 20 && y > rect.top - 20 && y < rect.bottom + 20){ return true; } return false; } private void pressLB(int x,int y){ float left = ChooseArea.left + x; float right = ChooseArea.right; float top = ChooseArea.top; float bottom = ChooseArea.bottom + y; if(left <= right - 30 && left >= dst.left && bottom <= dst.bottom && bottom >= top + 30){ ChooseArea.set(left,top,right,bottom); }else{ if(left + x < dst.left){ left = dst.left; } if(bottom + y > dst.bottom){ bottom = dst.bottom; } if(ChooseArea.left + x > ChooseArea.right - 30){ left = ChooseArea.right - 30; } if(ChooseArea.bottom + y < ChooseArea.top + 30){ bottom = ChooseArea.top + 30; } ChooseArea.set(left,top,right,bottom); } this.setPressRecLoc(); } private void pressLT(int x,int y){ float left = ChooseArea.left + x; float right = ChooseArea.right; float top = ChooseArea.top + y; float bottom = ChooseArea.bottom; if(left <= right - 30 && left >= dst.left && top <= bottom - 30 && top >= dst.top){ ChooseArea.set(left,top,right,bottom); }else{ if(left < dst.left){ left = dst.left; } if(top < dst.top){ top = dst.top; } if(left > right - 30){ left = right - 30; } if(top > bottom - 30){ top = bottom - 30; } ChooseArea.set(left,top,right,bottom); } this.setPressRecLoc(); } private void pressRT(int x,int y){ float left = ChooseArea.left; float right = ChooseArea.right + x; float top = ChooseArea.top + y; float bottom = ChooseArea.bottom; if(right <= dst.right && right >= left + 30 && top <= bottom - 30 && top >= dst.top){ ChooseArea.set(left,top,right,bottom); }else{ if(right > dst.right){ right = dst.right; } if(top < dst.top){ top = dst.top; } if(right < left + 30){ right = left + 30; } if(top > bottom - 30){ top = bottom - 30; } ChooseArea.set(left,top,right,bottom); } this.setPressRecLoc(); } private void pressRB(int x,int y){ float left = ChooseArea.left; float right = ChooseArea.right + x; float top = ChooseArea.top; float bottom = ChooseArea.bottom + y; if(right<= dst.right && right >= left + 30 && bottom <= dst.bottom && bottom >= top + 30){ ChooseArea.set(left,top,right,bottom); }else{ if(right > dst.right){ right = dst.right; } if(bottom > dst.bottom){ bottom = dst.bottom; } if(right < left + 30){ right = left + 30; } if(bottom < top + 30){ bottom = top + 30; } ChooseArea.set(left,top,right,bottom); } this.setPressRecLoc(); } //每次改变选择区域矩形的大小或者移动,各角落上的小矩形也要改变它的Location private void setPressRecLoc(){ recLT.set(ChooseArea.left-5,ChooseArea.top-5 , ChooseArea.left+5, ChooseArea.top+5); recLB.set(ChooseArea.left-5,ChooseArea.bottom-5 , ChooseArea.left+5, ChooseArea.bottom+5); recRT.set(ChooseArea.right-5,ChooseArea.top-5 , ChooseArea.right+5, ChooseArea.top+5); recRB.set(ChooseArea.right-5,ChooseArea.bottom-5 , ChooseArea.right+5, ChooseArea.bottom+5); } public boolean judgeLocation(float x,float y){ float start_x = this.getChooseArea().left; float start_y = this.getChooseArea().top; float last_x = this.getChooseArea().right; float last_y = this.getChooseArea().bottom; //System.out.println("chubi:" + x + "," + y); //System.out.println(start_y + "," + last_y); if(x > start_x+10 && x < last_x-10 && y > start_y+10 && y < last_y-10){ return true; } return false; } public void onDraw(Canvas canvas){ super.onDraw(canvas); if(firstFlag){ this.imageScale(); firstFlag = false; mPaint.setColor(Color.RED); System.out.println("Width: " + (dst.right - dst.left)); System.out.println("Height: " + (dst.bottom - dst.top)); System.out.println("Width: " + this.getDrawable().getIntrinsicWidth()); System.out.println("Height: " + this.getDrawable().getIntrinsicHeight()); }else{ set_LeftArea_Alpha(); } canvas.drawRect(ChooseArea, mPaint); mPaint.setColor(Color.BLUE); canvas.drawRect(recLT, mPaint); canvas.drawRect(recLB, mPaint); canvas.drawRect(recRT, mPaint); canvas.drawRect(recRB, mPaint); canvas.drawRect(leftRectL, leftAreaPaint); canvas.drawRect(leftRectR, leftAreaPaint); canvas.drawRect(leftRectT, leftAreaPaint); canvas.drawRect(leftRectB, leftAreaPaint); } public void set_LeftArea_Alpha(){ leftRectL.set(dst.left, dst.top, ChooseArea.left, dst.bottom); leftRectR.set(ChooseArea.right,dst.top,dst.right,dst.bottom); leftRectT.set(ChooseArea.left, dst.top, ChooseArea.right, ChooseArea.top); leftRectB.set(ChooseArea.left,ChooseArea.bottom,ChooseArea.right,dst.bottom); } }
播放幻灯片浏览图片再说明:
使用两个全局变量:
public String[] myImageNames; //所有的图片的名字
public int ImageNameId = 0; //图片编号
public String picfolderPath; //实际上是 文件夹 的路径
开个线程,每3秒显示一张图片:
ImagePath = picfolderPath + File.separator + myImageNames[ImageNameId];
ImageNameId++;
public String picfolderPath; //实际上是 文件夹 的路径 public String[] myImageNames; //所有的图片的名字 public int ImageNameId = 0; //图片编号 public String ImagePath ; //图片的路径 is = (ImageSwitcher) findViewById(R.id.slideshow_switcher); is.setFactory(this); is.setInAnimation(AnimationUtils.loadAnimation(this,android.R.anim.fade_in)); is.setOutAnimation(AnimationUtils.loadAnimation(this,android.R.anim.fade_out)); Runnable runnable=new Runnable() { //采用Handler的postDelayed(Runnable, long)方法 计时 @Override public void run() { // TODO Auto-generated method stub if(ImageNameId < myImageNames.length) { is.reset(); ImagePath = picfolderPath + File.separator + myImageNames[ImageNameId]; ImageNameId++; getSampledBitmap(ImagePath); } else if(ImageNameId ==myImageNames.length) { is.reset(); ImageNameId = 0; //重置 ImageNameId,实现循环播放 ImagePath = picfolderPath + File.separator + myImageNames[ImageNameId]; ImageNameId++; getSampledBitmap(ImagePath); } //handler.removeCallbacks(runnable);//停止计时器 //handler.postDelayed(this, 3000);//3秒时间间隔 } };