android图像绘制——画布保存为图片

Bitmap bmp = Bitmap.createBitmap(480, 800, Config.ARGB_8888); 
Canvas canvas = new Canvas(bmp); 
canvas.drawBitmap(this.bmp, matrix, paint); 
canvas.save(Canvas.ALL_SAVE_FLAG); 
canvas.restore(); 
 
File file = new File("/sdcard/akai/"); 
if(!file.exists()) 
file.mkdirs(); 
try { 
FileOutputStream fos = new FileOutputStream(file.getPath() + "/2.png"); 
bmp.compress(Bitmap.CompressFormat.PNG, 100, fos); 
fos.close(); 
System.out.println("saveBmp is here"); 
} catch (Exception e) { 
e.printStackTrace(); 
} 
Bitmap bmp = Bitmap.createBitmap(480, 800, Config.ARGB_8888);
Canvas canvas = new Canvas(bmp);
canvas.drawBitmap(this.bmp, matrix, paint);
canvas.save(Canvas.ALL_SAVE_FLAG);
canvas.restore();
   
File file = new File("/sdcard/akai/");
if(!file.exists())
 file.mkdirs();
 try {
  FileOutputStream fos = new FileOutputStream(file.getPath() + "/2.png");
  bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
  fos.close();
  System.out.println("saveBmp is here");
 } catch (Exception e) {
e.printStackTrace();
}

解释:

1、首先创建一个Bitmap图片,并指定大小;

2、在该图片上创建一个新的画布Canvas,然后在画布上绘制,并保存即可;

3、需要保存的目录File,注意如果写的目录如“/sdcard/akai/”如果不存在的话,要先创建(file.mkdirs()),否则FileOutputStream会报错No found;

4、需要添加权限:<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

android中的画布(Canvas)

什么是画布呢 其实通过字面意思的理解就是用来绘画的地方,那么android里的画布是神马样子的呢?

在自定义画布中常用到下面3个类

Canvas

   Canvas提供了绘图方法,可以向底层的位图绘制基本图形。
   Canvas类封装了用作绘图表面的位图;它还提供了draw*方法来实现设计。
   Canvas():创建一个空的画布,可以使用setBitmap()方法来设置绘制具体的画布。
   Canvas(Bitmapbitmap): 以bitmap对象创建一个画布,则将内容都绘制在bitmap上,因 此bitmap不得为null。
   drawARGB/ drawRGB / drawColor 使用单一的颜色填充画布。
   drawBitmap在画布上绘制一个位图。可以通过指定目标大小或者使用一个矩阵来改变目标位图的外观。
   drawBitmapMesh使用一个mesh(网)来绘制一个位图,它可以通过移动网中的点来操作  目标的外观。
   drawPaint使用指定的Paint填充整个Canvas
   drawPath绘制指定的Path。Path对象经常用来保存一个对象中基本图形的集合。
   drawPicture在指定的矩形中绘制一个Picture对象。
   drawPosText绘制指定了每一个字符的偏移量的文本字符串。
   drawRoundRect绘制一个圆角矩形。
   drawTextOnPath在一个指定的path上绘制文本。
   drawColor:设置Canvas的背景颜色。
   setBitmap:  设置具体画布。
   clipRect:设置显示区域,即设置裁剪区。
   isOpaque:检测是否支持透明。
   rotate:  旋转画布
   setViewport:  设置画布中显示窗口。
   skew:  设置偏移量。
   sava()保存画布当前的状态
   restore()操作之后取出之前保存过的状态

   还有很多这里就不列举了,详情请查看Android SDK

这些绘图方法中的每一个都需要指定一个Paint对象来渲染它

Paint

Paint也称为"刷子",Paint可以指定如何将基本图形绘制到位图上。

Paint类相当于一个笔刷和调色板。它可以选择如何使用上面描述的draw方法来渲染绘 制在画布上的基本图形。通过修改Paint对象,可以在绘图的时候控制颜色、样式、字体和特殊效果。最简单地,setColor可以让你选择一个Paint的颜色,而Paint对象的样式(使用setStyle控制)则可以决定是绘制绘图对象的轮廓(STROKE),还是只填充每一部 分(FILL),或者是两者都做(STROKE_AND_FILL)除了这些简单的控制之外,Paint类还支持透明度,另外,它也可以通过使用各种各样的阴影、过滤器和效果进行修改,从而提供由更丰富的、复杂的画笔和颜料组成的调色板。

从继承View类(或其子类)开始,并定义onDraw()回调方法。系统会调用该方法来完 成View对象自己的绘制请求。这也是通过Canvas对象来执行所有的图形绘制调用的地方,这个Canvas对象是由onDraw()回调方法传入的。

Android框架只在必要的时候才会调用onDraw()方法,每次请求应用程序准备完成图形 绘制任务时,必须通过调用invalidate()方法让该View对象失效。这表明可以在该View 对象上进行图形绘制处理了,然后Android系统会调用该View对象的onDraw()方(尽 管不保证该回调方法会立即被调用)。

在定制的View组件的onDraw()方法内部,使用给定的Canvas对象来完成所有的图形绘制处理(如Canvas.draw…()方法或把该Canvas对象作为参数传递给其他类的draw() 方法)。一旦onDraw()方法被执行完成,Android框架就会使用这个Canvas对象来绘制一个有系统处理的Bitmap对象。

下面是Paint一些常用方法:

  setAntiAlias:设置画笔的锯齿效果。
  setColor: 设置画笔颜色
  setARGB:  设置画笔的a,r,p,g值。
  setAlpha:  设置Alpha值
  setTextSize: 设置字体尺寸。
  setStyle:  设置画笔风格,空心或者实心。
  setStrokeWidth: 设置空心的边框宽度。
  getColor:  得到画笔的颜色
  getAlpha:  得到画笔的Alpha值。
  还有很多这里就不列举了,详情请查看Android SDK

Bitmap

Bitmap绘图的表面也称位图(这里详细说哈位图的功能)。

从资源中获取位图:

通过Resource的函数:InputStream openRawResource(int id)获取得到资源文件的数据流后,可以通过2种方式获得bitmap

使用BitmapDrawable :

使用BitmapDrawable(InputStream is)构造一个BitmapDrawable;

使用BitmapDrawable类的getBitmap()获取得到位图;

使用BitmapFactory使用BitmapFactory类decodeStream(InputStream is)解码位 图资源,获取位图BitmapFactory的所有函数都是static,这个辅助类可以通过资 源ID、路径、文件、数据流等方式来获取位图。

获取位图的信息

一般获取位图信息包括:位图大小、透明度、颜色格式等等,这些信息呢可以通过 三-一方法获取得到Bitmap就迎刃而解了,Android SDK中对Bitmap有详细说明,大家可以去详细了解哈。

显示位图

显示位图需要使用核心类Canvas,可以直接通过Canvas类的drawBirmap()显示位图,或者借助于BitmapDrawable来将Bitmap绘制到Canvas,下面的实例中会详细列举到

位图的缩放

位图的缩放,在Android SDK中提供了2种方法:

1:将一个位图按照需求重画一遍,画后的位图就是我们需要的了,与位图的显示几乎 一样:
drawBitmap(Bitmap bitmap, Rect src, Rectdst, Paint paint)

2:在原有位图的基础上,缩放原位图,创建一个新的位图:
createBitmap(Bitmap source, int x, int y,int width, int height, Matrix m, boolean filter)

位图旋转

位图的旋转,离不开Matrix。Android SDK提供了Matrix类,可以通过各种接口来设置 矩阵

android 处理图片工具

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Bitmap.Config;
import android.graphics.PorterDuff.Mode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;

/**
 * 处理图片的工具类.
 */
public class imageTool {
public static final int LEFT = 0;
public static final int RIGHT = 1;
public static final int TOP = 3;
public static final int BOTTOM = 4;

/** */
/**
 * 图片去色,返回灰度图片
 * 
 * @param bmpOriginal
 *传入的图片
 * @return 去色后的图片
 */
public static Bitmap toGrayscale(Bitmap bmpOriginal) {
int width, height;
height = bmpOriginal.getHeight();
width = bmpOriginal.getWidth();
Bitmap bmpGrayscale = Bitmap.createBitmap(width, height,
Bitmap.Config.RGB_565);
Canvas c = new Canvas(bmpGrayscale);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
paint.setColorFilter(f);
c.drawBitmap(bmpOriginal, 0, 0, paint);
return bmpGrayscale;
}

/** */
/**
 * 去色同时加圆角
 * 
 * @param bmpOriginal
 *原图
 * @param pixels
 *圆角弧度
 * @return 修改后的图片
 */
public static Bitmap toGrayscale(Bitmap bmpOriginal, int pixels) {
return toRoundCorner(toGrayscale(bmpOriginal), pixels);
}

/** */
/**
 * 把图片变成圆角
 * 
 * @param bitmap
 *需要修改的图片
 * @param pixels
 *圆角的弧度
 * @return 圆角图片
 */
public static Bitmap toRoundCorner(Bitmap bitmap, int pixels) {
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap
.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
final RectF rectF = new RectF(rect);
final float roundPx = pixels;
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}

/** */
/**
 * 使圆角功能支持BitampDrawable
 * 
 * @param bitmapDrawable
 * @param pixels
 * @return
 */
public static BitmapDrawable toRoundCorner(BitmapDrawable bitmapDrawable,
int pixels) {
Bitmap bitmap = bitmapDrawable.getBitmap();
bitmapDrawable = new BitmapDrawable(toRoundCorner(bitmap, pixels));
return bitmapDrawable;
}

/**
 * 读取路径中的图片,然后将其转化为缩放后的bitmap
 * 
 * @param path
 */
public static void saveBefore(String path) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
// 获取这个图片的宽和高
Bitmap bitmap = BitmapFactory.decodeFile(path, options); // 此时返回bm为空
options.inJustDecodeBounds = false;
// 计算缩放比
int be = (int) (options.outHeight / (float) 200);
if (be <= 0)
be = 1;
options.inSampleSize = 2; // 图片长宽各缩小二分之一
// 重新读入图片,注意这次要把options.inJustDecodeBounds 设为 false哦
bitmap = BitmapFactory.decodeFile(path, options);
int w = bitmap.getWidth();
int h = bitmap.getHeight();
System.out.println(w + " " + h);
// savePNG_After(bitmap,path);
saveJPGE_After(bitmap, path);
}

/**
 * 保存图片为PNG
 * 
 * @param bitmap
 * @param name
 */
public static void savePNG_After(Bitmap bitmap, String name) {
File file = new File(name);
try {
FileOutputStream out = new FileOutputStream(file);
if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, out)) {
out.flush();
out.close();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

/**
 * 保存图片为JPEG
 * 
 * @param bitmap
 * @param path
 */
public static void saveJPGE_After(Bitmap bitmap, String path) {
File file = new File(path);
try {
FileOutputStream out = new FileOutputStream(file);
if (bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out)) {
out.flush();
out.close();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

/**
 * 水印
 * 
 * @param bitmap
 * @return
 */
public static Bitmap createBitmapForWatermark(Bitmap src, Bitmap watermark) {
if (src == null) {
return null;
}
int w = src.getWidth();
int h = src.getHeight();
int ww = watermark.getWidth();
int wh = watermark.getHeight();
// create the new blank bitmap
Bitmap newb = Bitmap.createBitmap(w, h, Config.ARGB_8888);// 创建一个新的和SRC长度宽度一样的位图
Canvas cv = new Canvas(newb);
// draw src into
cv.drawBitmap(src, 0, 0, null);// 在 0,0坐标开始画入src
// draw watermark into
cv.drawBitmap(watermark, w - ww + 5, h - wh + 5, null);// 在src的右下角画入水印
// save all clip
cv.save(Canvas.ALL_SAVE_FLAG);// 保存
// store
cv.restore();// 存储
return newb;
}

/**
 * 图片合成
 * 
 * @return
 */
public static Bitmap potoMix(int direction, Bitmap... bitmaps) {
if (bitmaps.length <= 0) {
return null;
}
if (bitmaps.length == 1) {
return bitmaps[0];
}
Bitmap newBitmap = bitmaps[0];
// newBitmap = createBitmapForFotoMix(bitmaps[0],bitmaps[1],direction);
for (int i = 1; i < bitmaps.length; i++) {
newBitmap = createBitmapForFotoMix(newBitmap, bitmaps[i], direction);
}
return newBitmap;
}

private static Bitmap createBitmapForFotoMix(Bitmap first, Bitmap second,
int direction) {
if (first == null) {
return null;
}
if (second == null) {
return first;
}
int fw = first.getWidth();
int fh = first.getHeight();
int sw = second.getWidth();
int sh = second.getHeight();
Bitmap newBitmap = null;
if (direction == LEFT) {
newBitmap = Bitmap.createBitmap(fw + sw, fh > sh ? fh : sh,
Config.ARGB_8888);
Canvas canvas = new Canvas(newBitmap);
canvas.drawBitmap(first, sw, 0, null);
canvas.drawBitmap(second, 0, 0, null);
} else if (direction == RIGHT) {
newBitmap = Bitmap.createBitmap(fw + sw, fh > sh ? fh : sh,
Config.ARGB_8888);
Canvas canvas = new Canvas(newBitmap);
canvas.drawBitmap(first, 0, 0, null);
canvas.drawBitmap(second, fw, 0, null);
} else if (direction == TOP) {
newBitmap = Bitmap.createBitmap(sw > fw ? sw : fw, fh + sh,
Config.ARGB_8888);
Canvas canvas = new Canvas(newBitmap);
canvas.drawBitmap(first, 0, sh, null);
canvas.drawBitmap(second, 0, 0, null);
} else if (direction == BOTTOM) {
newBitmap = Bitmap.createBitmap(sw > fw ? sw : fw, fh + sh,
Config.ARGB_8888);
Canvas canvas = new Canvas(newBitmap);
canvas.drawBitmap(first, 0, 0, null);
canvas.drawBitmap(second, 0, fh, null);
}
return newBitmap;
}

/**
 * 将Bitmap转换成指定大小
 * 
 * @param bitmap
 * @param width
 * @param height
 * @return
 */
public static Bitmap createBitmapBySize(Bitmap bitmap, int width, int height) {
return Bitmap.createScaledBitmap(bitmap, width, height, true);
}

/**
 * Drawable 转 Bitmap
 * 
 * @param drawable
 * @return
 */
public static Bitmap drawableToBitmapByBD(Drawable drawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
return bitmapDrawable.getBitmap();
}

/**
 * Bitmap 转 Drawable
 * 
 * @param bitmap
 * @return
 */
public static Drawable bitmapToDrawableByBD(Bitmap bitmap) {
Drawable drawable = new BitmapDrawable(bitmap);
return drawable;
}

/**
 * byte[] 转 bitmap
 * 
 * @param b
 * @return
 */
public static Bitmap bytesToBimap(byte[] b) {
if (b.length != 0) {
return BitmapFactory.decodeByteArray(b, 0, b.length);
} else {
return null;
}
}

/**
 * bitmap 转 byte[]
 * 
 * @param bm
 * @return
 */
public static byte[] bitmapToBytes(Bitmap bm) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.PNG, 100, baos);
return baos.toByteArray();
}
}

截取视频帧并转化为Bitmap

/**
 * Demo描述:
 * 利用MediaMetadataRetriever按照时间截取视频
 * 并转换为Bitmap存放于SDCard
 * 
 * 特别注意:
 * getFrameAtTime()方法第一个参数的单位是微秒 (us)
 * 
 */
public void getBitmapsFromVideo() {
        String dataPath = Environment.getExternalStorageDirectory()+ "/testVideo.mp4";
        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
        retriever.setDataSource(dataPath);
        // 取得视频的长度(单位为毫秒)
        String time = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
        // 取得视频的长度(单位为秒)
        int seconds = Integer.valueOf(time) / 1000;
        // 得到每一秒时刻的bitmap比如第一秒,第二秒
        for (int i = 1; i <= seconds; i++) {
            Bitmap bitmap = retriever.getFrameAtTime(i*1000*1000,MediaMetadataRetriever.OPTION_CLOSEST_SYNC);
            String path = Environment.getExternalStorageDirectory()+ File.separator + i + ".jpg";
            FileOutputStream fos = null;
            try {
                fos = new FileOutputStream(path);
                bitmap.compress(CompressFormat.JPEG, 80, fos);
                fos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容