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秒时间间隔
  }
};
上一篇:SSH 25 tips


下一篇:[Functional Programming] Draw Items from One JavaScript Array to Another using a Pair ADT